diff --git a/package-lock.json b/package-lock.json
index 2a99a2099..0d599f9ec 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -61,6 +61,9 @@
"@types/jquery": "^3.5.29",
"eslint": "^8.55.0",
"jquery": "^3.6.4"
+ },
+ "engines": {
+ "node": ">= 18"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -3885,7 +3888,6 @@
},
"node_modules/punycode": {
"version": "2.3.1",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -4435,8 +4437,15 @@
}
},
"node_modules/tr46": {
- "version": "0.0.3",
- "license": "MIT"
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
+ "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
+ "dependencies": {
+ "punycode": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
},
"node_modules/truncate-utf8-bytes": {
"version": "1.0.2",
@@ -4585,19 +4594,27 @@
}
},
"node_modules/webidl-conversions": {
- "version": "3.0.1",
- "license": "BSD-2-Clause"
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+ "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
+ "engines": {
+ "node": ">=12"
+ }
},
"node_modules/whatwg-fetch": {
"version": "3.6.18",
"license": "MIT"
},
"node_modules/whatwg-url": {
- "version": "5.0.0",
- "license": "MIT",
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
+ "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
"dependencies": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
+ "tr46": "^5.0.0",
+ "webidl-conversions": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/which": {
diff --git a/package.json b/package.json
index e8cbda243..03a314006 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,9 @@
"yargs": "^17.7.1",
"yauzl": "^2.10.0"
},
+ "engines": {
+ "node": ">= 18"
+ },
"overrides": {
"parse-bmfont-xml": {
"xml2js": "^0.5.0"
@@ -59,6 +62,9 @@
},
"@zeldafan0225/ai_horde": {
"esbuild": "npm:dry-uninstall"
+ },
+ "node-fetch": {
+ "whatwg-url": "^14.0.0"
}
},
"name": "sillytavern",
diff --git a/public/index.html b/public/index.html
index 5c2f065d7..63c1d8fa8 100644
--- a/public/index.html
+++ b/public/index.html
@@ -6279,11 +6279,11 @@
+
-
diff --git a/public/script.js b/public/script.js
index 9355f5a35..62bf171df 100644
--- a/public/script.js
+++ b/public/script.js
@@ -1547,6 +1547,13 @@ function getCharacterSource(chId = this_chid) {
return sourceUrl;
}
+ const risuId = characters[chId]?.data?.extensions?.risuai?.source;
+
+ if (Array.isArray(risuId) && risuId.length && typeof risuId[0] === 'string' && risuId[0].startsWith('risurealm:')) {
+ const realmId = risuId[0].split(':')[1];
+ return `https://realm.risuai.net/character/${realmId}`;
+ }
+
return '';
}
@@ -5938,7 +5945,7 @@ export function changeMainAPI() {
getStatusHorde();
getHordeModels(true);
}
- validateDisabledSamplers()
+ validateDisabledSamplers();
setupChatCompletionPromptManager(oai_settings);
forceCharacterEditorTokenize();
}
@@ -6169,7 +6176,7 @@ export async function getSettings() {
firstRun = false;
}
}
- await validateDisabledSamplers()
+ await validateDisabledSamplers();
settingsReady = true;
eventSource.emit(event_types.SETTINGS_LOADED);
}
@@ -10240,19 +10247,8 @@ jQuery(async function () {
if (power_user.zoomed_avatar_magnification) {
$('.zoomed_avatar_container').izoomify();
- } else {
- $(`.zoomed_avatar[forChar="${charname}"] .dragClose`).hide();
}
- $('.zoomed_avatar').on('mouseup', (e) => {
- if (e.target.closest('.drag-grabber') || e.button !== 0) {
- return;
- }
- $(`.zoomed_avatar[forChar="${charname}"]`).fadeOut(animation_duration, () => {
- $(`.zoomed_avatar[forChar="${charname}"]`).remove();
- });
- });
-
$('.zoomed_avatar, .zoomed_avatar .dragClose').on('click touchend', (e) => {
if (e.target.closest('.dragClose')) {
$(`.zoomed_avatar[forChar="${charname}"]`).fadeOut(animation_duration, () => {
diff --git a/public/scripts/RossAscends-mods.js b/public/scripts/RossAscends-mods.js
index c08378ee9..b0a48d77f 100644
--- a/public/scripts/RossAscends-mods.js
+++ b/public/scripts/RossAscends-mods.js
@@ -424,7 +424,7 @@ function restoreUserInput() {
const userInput = LoadLocal('userInput');
if (userInput) {
- $('#send_textarea').val(userInput)[0].dispatchEvent(new Event('input', { bubbles:true }));
+ $('#send_textarea').val(userInput)[0].dispatchEvent(new Event('input', { bubbles: true }));
}
}
@@ -436,8 +436,6 @@ const saveUserInputDebounced = debounce(saveUserInput);
// Make the DIV element draggable:
-// THIRD UPDATE, prevent resize window breaks and smartly handle saving
-
export function dragElement(elmnt) {
var hasBeenDraggedByUser = false;
var isMouseDown = false;
@@ -479,8 +477,8 @@ export function dragElement(elmnt) {
}
//console.debug(left + width, winWidth, hasBeenDraggedByUser, isMouseDown)
const style = getComputedStyle(target); //use computed values because not all CSS are set by default
- height = target.offsetHeight;
- width = target.offsetWidth;
+ height = parseInt(style.height) //target.offsetHeight;
+ width = parseInt(style.width) //target.offsetWidth;
top = parseInt(style.top);
left = parseInt(style.left);
right = parseInt(style.right);
@@ -494,19 +492,20 @@ export function dragElement(elmnt) {
const topbarstyle = getComputedStyle(topbar);
topBarFirstX = parseInt(topbarstyle.marginInline);
topBarLastY = parseInt(topbarstyle.height);
-
- /*console.log(`
- winWidth: ${winWidth}, winHeight: ${winHeight}
- sheldWidth: ${sheldWidth}
- X: ${$(elmnt).css('left')}
- Y: ${$(elmnt).css('top')}
- MaxX: ${maxX}, MaxY: ${maxY}
- height: ${height}
- width: ${width}
- Topbar 1st X: ${topBarFirstX}
- TopBar lastX: ${topBarLastX}
- `);*/
-
+ /*
+ console.log(`
+ Observer
+ winWidth: ${winWidth}, winHeight: ${winHeight}
+ sheldWidth: sheldWidth
+ X: ${$(elmnt).css('left')}
+ Y: ${$(elmnt).css('top')}
+ MaxX: ${maxX}, MaxY: ${maxY}
+ height: ${height}
+ width: ${width}
+ Topbar 1st X: ${topBarFirstX}
+ TopBar lastX: topBarLastX
+ `);
+ */
//prepare an empty poweruser object for the item being altered if we don't have one already
if (!power_user.movingUIState[elmntName]) {
@@ -524,24 +523,38 @@ export function dragElement(elmnt) {
}
//handle resizing
- if (!hasBeenDraggedByUser && isMouseDown) {
- console.debug('saw resize, NOT header drag');
+ if (!hasBeenDraggedByUser && isMouseDown) { //if user is dragging the resize handle (not in header)
+ //console.debug('saw resize, NOT header drag');
+ let imgHeight, imgWidth, imageAspectRatio;
+ let containerAspectRatio = elmnt.height() / elmnt.width();
+
+ //force the zoomed avatar container to always be the same aspect ratio as the inner image
+ if ($(elmnt).attr('id').startsWith('zoomFor_')) {
+ let zoomedAvatarImage = $(elmnt).find('.zoomed_avatar_img');
+ imgHeight = zoomedAvatarImage.height();
+ imgWidth = zoomedAvatarImage.width();
+ imageAspectRatio = imgHeight / imgWidth;
+ }
+
+ if (containerAspectRatio !== imageAspectRatio) {
+ elmnt.css('height', imgHeight);
+ }
//prevent resizing offscreen
if (top + elmnt.height() >= winHeight) {
- console.debug('resizing height to prevent offscreen');
+ //console.debug('resizing height to prevent offscreen');
elmnt.css('height', winHeight - top - 1 + 'px');
}
if (left + elmnt.width() >= winWidth) {
- console.debug('resizing width to prevent offscreen');
+ //console.debug('resizing width to prevent offscreen');
elmnt.css('width', winWidth - left - 1 + 'px');
}
//prevent resizing from top left into the top bar
if (top < topBarLastY && maxX >= topBarFirstX && left <= topBarFirstX
) {
- console.debug('prevent topbar underlap resize');
+ //console.debug('prevent topbar underlap resize');
elmnt.css('width', width - 1 + 'px');
}
@@ -647,19 +660,20 @@ export function dragElement(elmnt) {
// and will defaults to shrink to min value of 100px set in CSS file
elmnt.css('height', height);
elmnt.css('width', width);
- /*
- console.log(`
- winWidth: ${winWidth}, winHeight: ${winHeight}
- sheldWidth: ${sheldWidth}
- X: ${$(elmnt).css('left')}
- Y: ${$(elmnt).css('top')}
- MaxX: ${maxX}, MaxY: ${maxY}
- height: ${height}
- width: ${width}
- Topbar 1st X: ${topBarFirstX}
- TopBar lastX: ${topBarLastX}
- `);
- */
+
+ /*console.log(`
+elementDrag:
+winWidth: ${winWidth}, winHeight: ${winHeight}
+sheldWidth: sheldWidth
+X: ${$(elmnt).css('left')}
+Y: ${$(elmnt).css('top')}
+MaxX: ${maxX}, MaxY: ${maxY}
+height: ${height}
+width: ${width}
+Topbar 1st X: ${topBarFirstX}
+TopBar lastX: topBarLastX
+`);*/
+
return;
}
diff --git a/public/scripts/char-data.js b/public/scripts/char-data.js
index 20db48c0a..ce5d55446 100644
--- a/public/scripts/char-data.js
+++ b/public/scripts/char-data.js
@@ -73,6 +73,7 @@
* @property {string} [github_repo] - The gitHub repository associated with the character.
* @property {string} [source_url] - The source URL associated with the character.
* @property {{full_path: string}} [chub] - The Chub-specific data associated with the character.
+ * @property {{source: string[]}} [risuai] - The RisuAI-specific data associated with the character.
*/
/**
diff --git a/public/scripts/extensions/tts/gsvi.js b/public/scripts/extensions/tts/gsvi.js
new file mode 100644
index 000000000..8aee4ad20
--- /dev/null
+++ b/public/scripts/extensions/tts/gsvi.js
@@ -0,0 +1,267 @@
+
+import { saveTtsProviderSettings } from './index.js';
+
+export { GSVITtsProvider };
+
+class GSVITtsProvider {
+ //########//
+ // Config //
+ //########//
+
+ settings;
+ ready = false;
+ separator = '. ';
+
+ characterList = {};
+ voices = [];
+ /**
+ * Perform any text processing before passing to TTS engine.
+ * @param {string} text Input text
+ * @returns {string} Processed text
+ */
+ processText(text) {
+ text = text.replace('
', '\n'); // Replace
with newline
+ return text;
+ }
+
+ languageLabels = {
+ 'Multilingual': '多语种混合',
+ 'Chinese': '中文',
+ 'English': '英文',
+ 'Japanese': '日文',
+ 'Chinese-English': '中英混合',
+ 'Japanese-English': '日英混合',
+ };
+ defaultSettings = {
+ provider_endpoint: 'http://127.0.0.1:5000',
+
+ language: '多语种混合',
+
+ cha_name: '',
+ character_emotion: 'default',
+
+ speed: 1,
+
+ top_k: 6,
+ top_p: 0.85,
+ temperature: 0.75,
+ batch_size: 10,
+
+ stream: false,
+ stream_chunk_size: 100,
+ };
+
+ // Added new methods to obtain characters and emotions
+ async fetchCharacterList() {
+ const response = await fetch(this.settings.provider_endpoint + '/character_list');
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${await response.text()}`);
+ }
+ const characterList = await response.json();
+ this.characterList = characterList;
+ this.voices = Object.keys(characterList);
+
+ }
+
+
+
+ get settingsHtml() {
+ let html = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ For more information, visit the
+ GSVI project page.
+
+ `;
+
+ return html;
+ }
+
+ onSettingsChange() {
+ // Update provider settings based on input fields
+ this.settings.provider_endpoint = $('#gsvi_tts_endpoint').val();
+ this.settings.language = $('#gsvi_api_language').val();
+
+
+ // Update the rest of TTS settings based on input fields
+ this.settings.speed = parseFloat($('#gsvi_speed').val());
+ this.settings.temperature = parseFloat($('#gsvi_temperature').val());
+ this.settings.top_k = parseInt($('#gsvi_top_k').val(), 10);
+ this.settings.top_p = parseFloat($('#gsvi_top_p').val());
+ this.settings.batch_size = parseInt($('#gsvi_batch_size').val(), 10);
+ this.settings.stream = $('#gsvi_tts_streaming').is(':checked');
+ this.settings.stream_chunk_size = parseInt($('#gsvi_stream_chunk_size').val(), 10);
+
+ // Update UI to reflect changes
+
+ $('#gsvi_tts_speed_output').text(this.settings.speed);
+ $('#gsvi_tts_temperature_output').text(this.settings.temperature);
+ $('#gsvi_top_k_output').text(this.settings.top_k);
+ $('#gsvi_top_p_output').text(this.settings.top_p);
+ $('#gsvi_stream_chunk_size_output').text(this.settings.stream_chunk_size);
+ $('#gsvi_batch_size_output').text(this.settings.batch_size);
+
+
+
+
+ // Persist settings changes
+ saveTtsProviderSettings();
+
+ }
+
+ async loadSettings(settings) {
+ // Populate 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, ...settings };
+
+ // Fetch character and emotion list
+ // Set initial values from the settings
+ $('#gsvi_tts_endpoint').val(this.settings.provider_endpoint);
+ $('#gsvi_api_language').val(this.settings.language);
+
+ $('#gsvi_speed').val(this.settings.speed);
+ $('#gsvi_temperature').val(this.settings.temperature);
+ $('#gsvi_top_k').val(this.settings.top_k);
+ $('#gsvi_top_p').val(this.settings.top_p);
+ $('#gsvi_batch_size').val(this.settings.batch_size);
+ $('#gsvi_tts_streaming').prop('checked', this.settings.stream);
+ $('#gsvi_stream_chunk_size').val(this.settings.stream_chunk_size);
+
+ // Update UI to reflect initial settings
+ $('#gsvi_tts_speed_output').text(this.settings.speed);
+ $('#gsvi_tts_temperature_output').text(this.settings.temperature);
+ $('#gsvi_top_k_output').text(this.settings.top_k);
+ $('#gsvi_top_p_output').text(this.settings.top_p);
+ $('#gsvi_stream_chunk_size_output').text(this.settings.stream_chunk_size);
+
+ // Register event listeners to update settings on user interaction
+ // (Similar to before, ensure event listeners for character and emotion selection are included)
+ // Register input/change event listeners to update settings on user interaction
+ $('#gsvi_tts_endpoint').on('input', () => { this.onSettingsChange(); });
+ $('#gsvi_api_language').on('change', () => { this.onSettingsChange(); });
+
+ $('#gsvi_speed').on('input', () => { this.onSettingsChange(); });
+ $('#gsvi_temperature').on('input', () => { this.onSettingsChange(); });
+ $('#gsvi_top_k').on('input', () => { this.onSettingsChange(); });
+ $('#gsvi_top_p').on('input', () => { this.onSettingsChange(); });
+ $('#gsvi_batch_size').on('input', () => { this.onSettingsChange(); });
+ $('#gsvi_tts_streaming').on('change', () => { this.onSettingsChange(); });
+ $('#gsvi_stream_chunk_size').on('input', () => { this.onSettingsChange(); });
+
+ await this.checkReady();
+ console.debug('GSVI: Settings loaded');
+ }
+
+
+
+ // Perform a simple readiness check by trying to fetch voiceIds
+ async checkReady() {
+ await Promise.allSettled([this.fetchCharacterList()]);
+ }
+
+ async onRefreshClick() {
+ return;
+ }
+
+ //#################//
+ // TTS Interfaces //
+ //#################//
+
+ async getVoice(voiceName) {
+ if (this.voices.length == 0) {
+ this.fetchCharacterList();
+ }
+ if (!this.voices.includes(voiceName)) {
+ throw `TTS Voice name ${voiceName} not found`;
+ }
+ return { name: voiceName, voice_id: voiceName, preview_url: false, lang: 'zh-CN' };
+ }
+
+ async generateTts(text, voiceId) {
+ const response = await this.fetchTtsGeneration(text, voiceId);
+ return response;
+ }
+
+ //###########//
+ // API CALLS //
+ //###########//
+ async fetchTtsVoiceObjects() {
+ if (this.voices.length == 0) {
+ await this.fetchCharacterList();
+ }
+ console.log(this.voices);
+ const voices = this.voices.map(x => ({ name: x, voice_id: x, preview_url: false, lang: 'zh-CN' }));
+ return voices;
+ }
+
+
+ async fetchTtsGeneration(inputText, voiceId) {
+ console.info(`Generating new TTS for voice_id ${voiceId}`);
+
+
+ const params = new URLSearchParams();
+ params.append('text', inputText);
+ params.append('cha_name', voiceId);
+ params.append('text_language', this.settings.language);
+ params.append('batch_size', this.settings.batch_size.toString());
+ params.append('speed', this.settings.speed.toString());
+ params.append('top_k', this.settings.top_k.toString());
+ params.append('top_p', this.settings.top_p.toString());
+ params.append('temperature', this.settings.temperature.toString());
+ params.append('stream', this.settings.stream.toString());
+
+
+ return `${this.settings.provider_endpoint}/tts?${params.toString()}`;
+
+ }
+
+ // Interface not used by GSVI TTS
+ async fetchTtsFromHistory(history_item_id) {
+ return Promise.resolve(history_item_id);
+ }
+
+}
diff --git a/public/scripts/extensions/tts/index.js b/public/scripts/extensions/tts/index.js
index 2aa0de82f..f73e9d48f 100644
--- a/public/scripts/extensions/tts/index.js
+++ b/public/scripts/extensions/tts/index.js
@@ -10,6 +10,7 @@ import { NovelTtsProvider } from './novel.js';
import { power_user } from '../../power-user.js';
import { OpenAITtsProvider } from './openai.js';
import { XTTSTtsProvider } from './xtts.js';
+import { GSVITtsProvider } from './gsvi.js';
import { AllTalkTtsProvider } from './alltalk.js';
import { SpeechT5TtsProvider } from './speecht5.js';
import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
@@ -74,6 +75,7 @@ const ttsProviders = {
ElevenLabs: ElevenLabsTtsProvider,
Silero: SileroTtsProvider,
XTTSv2: XTTSTtsProvider,
+ GSVI: GSVITtsProvider,
System: SystemTtsProvider,
Coqui: CoquiTtsProvider,
Edge: EdgeTtsProvider,
diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js
index 93186df20..ca72682cd 100644
--- a/public/scripts/power-user.js
+++ b/public/scripts/power-user.js
@@ -1389,7 +1389,7 @@ async function applyTheme(name) {
}
async function applyMovingUIPreset(name) {
- resetMovablePanels('quiet');
+ await resetMovablePanels('quiet');
const movingUIPreset = movingUIPresets.find(x => x.name == name);
if (!movingUIPreset) {
@@ -1401,6 +1401,7 @@ async function applyMovingUIPreset(name) {
console.log('MovingUI Preset applied: ' + name);
loadMovingUIState();
+ saveSettingsDebounced()
}
/**
@@ -1629,9 +1630,9 @@ function loadPowerUserSettings(settings, data) {
$('#stscript_autocomplete_font_scale_counter').val(power_user.stscript.autocomplete.font.scale ?? defaultStscript.autocomplete.font.scale);
document.body.style.setProperty('--ac-font-scale', power_user.stscript.autocomplete.font.scale ?? defaultStscript.autocomplete.font.scale.toString());
$('#stscript_autocomplete_width_left').val(power_user.stscript.autocomplete.width.left ?? AUTOCOMPLETE_WIDTH.CHAT);
- document.querySelector('#stscript_autocomplete_width_left').dispatchEvent(new Event('input', { bubbles:true }));
+ document.querySelector('#stscript_autocomplete_width_left').dispatchEvent(new Event('input', { bubbles: true }));
$('#stscript_autocomplete_width_right').val(power_user.stscript.autocomplete.width.right ?? AUTOCOMPLETE_WIDTH.CHAT);
- document.querySelector('#stscript_autocomplete_width_right').dispatchEvent(new Event('input', { bubbles:true }));
+ document.querySelector('#stscript_autocomplete_width_right').dispatchEvent(new Event('input', { bubbles: true }));
$('#restore_user_input').prop('checked', power_user.restore_user_input);
@@ -3671,7 +3672,7 @@ $(document).ready(() => {
$('#stscript_autocomplete_font_scale_counter').val(value);
power_user.stscript.autocomplete.font.scale = Number(value);
document.body.style.setProperty('--ac-font-scale', value.toString());
- window.dispatchEvent(new Event('resize', { bubbles:true }));
+ window.dispatchEvent(new Event('resize', { bubbles: true }));
saveSettingsDebounced();
});
$('#stscript_autocomplete_font_scale_counter').on('input', function () {
@@ -3679,7 +3680,7 @@ $(document).ready(() => {
$('#stscript_autocomplete_font_scale').val(value);
power_user.stscript.autocomplete.font.scale = Number(value);
document.body.style.setProperty('--ac-font-scale', value.toString());
- window.dispatchEvent(new Event('resize', { bubbles:true }));
+ window.dispatchEvent(new Event('resize', { bubbles: true }));
saveSettingsDebounced();
});
@@ -3687,7 +3688,7 @@ $(document).ready(() => {
const value = $(this).val();
power_user.stscript.autocomplete.width.left = Number(value);
/**@type {HTMLElement}*/(this.closest('.doubleRangeInputContainer')).style.setProperty('--value', value.toString());
- window.dispatchEvent(new Event('resize', { bubbles:true }));
+ window.dispatchEvent(new Event('resize', { bubbles: true }));
saveSettingsDebounced();
});
@@ -3695,7 +3696,7 @@ $(document).ready(() => {
const value = $(this).val();
power_user.stscript.autocomplete.width.right = Number(value);
/**@type {HTMLElement}*/(this.closest('.doubleRangeInputContainer')).style.setProperty('--value', value.toString());
- window.dispatchEvent(new Event('resize', { bubbles:true }));
+ window.dispatchEvent(new Event('resize', { bubbles: true }));
saveSettingsDebounced();
});
@@ -3789,15 +3790,18 @@ $(document).ready(() => {
browser_has_focus = false;
});
- SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'vn',
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'vn',
callback: toggleWaifu,
helpString: 'Swaps Visual Novel Mode On/Off',
}));
- SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'newchat',
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'newchat',
callback: doNewChat,
helpString: 'Start a new chat with the current character',
}));
- SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'random',
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'random',
callback: doRandomChat,
unnamedArgumentList: [
new SlashCommandArgument(
@@ -3806,7 +3810,8 @@ $(document).ready(() => {
],
helpString: 'Start a new chat with a random character. If an argument is provided, only considers characters that have the specified tag.',
}));
- SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'delmode',
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'delmode',
callback: doDelMode,
aliases: ['del'],
unnamedArgumentList: [
@@ -3816,7 +3821,8 @@ $(document).ready(() => {
],
helpString: 'Enter message deletion mode, and auto-deletes last N messages if numeric argument is provided.',
}));
- SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'cut',
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'cut',
callback: doMesCut,
returns: 'the text of cut messages separated by a newline',
unnamedArgumentList: [
@@ -3842,16 +3848,19 @@ $(document).ready(() => {
`,
aliases: [],
}));
- SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'resetpanels',
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'resetpanels',
callback: doResetPanels,
helpString: 'resets UI panels to original state',
aliases: ['resetui'],
}));
- SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'bgcol',
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'bgcol',
callback: setAvgBG,
helpString: '– WIP test of auto-bg avg coloring',
}));
- SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'theme',
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'theme',
callback: setThemeCallback,
unnamedArgumentList: [
new SlashCommandArgument(
@@ -3860,7 +3869,8 @@ $(document).ready(() => {
],
helpString: 'sets a UI theme by name',
}));
- SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'movingui',
+ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'movingui',
callback: setmovingUIPreset,
unnamedArgumentList: [
new SlashCommandArgument(
diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js
index be75a9561..d273130fa 100644
--- a/public/scripts/slash-commands.js
+++ b/public/scripts/slash-commands.js
@@ -73,7 +73,8 @@ export const parser = new SlashCommandParser();
const registerSlashCommand = SlashCommandParser.addCommand.bind(SlashCommandParser);
const getSlashCommandsHelp = parser.getHelpString.bind(parser);
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: '?',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: '?',
callback: helpCommandCallback,
aliases: ['help'],
unnamedArgumentList: [new SlashCommandArgument(
@@ -81,7 +82,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: '?',
)],
helpString: 'Get help on macros, chat formatting and commands.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'name',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'name',
callback: setNameCallback,
unnamedArgumentList: [
new SlashCommandArgument(
@@ -91,16 +93,19 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'name',
helpString: 'Sets user name and persona avatar (if set).',
aliases: ['persona'],
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sync',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'sync',
callback: syncCallback,
helpString: 'Syncs the user persona in user-attributed messages in the current chat.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'lock',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'lock',
callback: bindCallback,
aliases: ['bind'],
helpString: 'Locks/unlocks a persona (name and avatar) to the current chat',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'bg',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'bg',
callback: setBackgroundCallback,
aliases: ['background'],
returns: 'the current background',
@@ -123,7 +128,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'bg',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sendas',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'sendas',
callback: sendMessageAs,
namedArgumentList: [
new SlashCommandNamedArgument(
@@ -161,7 +167,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sendas',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sys',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'sys',
callback: sendNarratorMessage,
aliases: ['nar'],
namedArgumentList: [
@@ -204,7 +211,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sys',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sysname',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'sysname',
callback: setNarratorName,
unnamedArgumentList: [
new SlashCommandArgument(
@@ -213,7 +221,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sysname',
],
helpString: 'Sets a name for future system narrator messages in this chat (display only). Default: System. Leave empty to reset.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'comment',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'comment',
callback: sendCommentMessage,
namedArgumentList: [
new SlashCommandNamedArgument(
@@ -257,22 +266,26 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'comment',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'single',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'single',
callback: setStoryModeCallback,
aliases: ['story'],
helpString: 'Sets the message style to single document mode without names or avatars visible.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'bubble',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'bubble',
callback: setBubbleModeCallback,
aliases: ['bubbles'],
helpString: 'Sets the message style to bubble chat mode.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'flat',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'flat',
callback: setFlatModeCallback,
aliases: ['default'],
helpString: 'Sets the message style to flat chat mode.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'continue',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'continue',
callback: continueChatCallback,
aliases: ['cont'],
unnamedArgumentList: [
@@ -299,7 +312,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'continue',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'go',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'go',
callback: goToCharacterCallback,
unnamedArgumentList: [
new SlashCommandArgument(
@@ -309,7 +323,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'go',
helpString: 'Opens up a chat with the character or group by its name',
aliases: ['char'],
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sysgen',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'sysgen',
callback: generateSystemMessage,
unnamedArgumentList: [
new SlashCommandArgument(
@@ -318,7 +333,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sysgen',
],
helpString: 'Generates a system message using a specified prompt.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'ask',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'ask',
callback: askCharacter,
unnamedArgumentList: [
new SlashCommandArgument(
@@ -330,7 +346,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'ask',
],
helpString: 'Asks a specified character card a prompt. Character name and prompt have to be separated by a new line.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'delname',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'delname',
callback: deleteMessagesByNameCallback,
namedArgumentList: [],
unnamedArgumentList: [
@@ -353,7 +370,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'delname',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'send',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'send',
callback: sendUserMessageCallback,
namedArgumentList: [
new SlashCommandNamedArgument(
@@ -408,7 +426,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'send',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trigger',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'trigger',
callback: triggerGenerationCallback,
namedArgumentList: [
new SlashCommandNamedArgument(
@@ -429,7 +448,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trigger',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'hide',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'hide',
callback: hideMessageCallback,
unnamedArgumentList: [
new SlashCommandArgument(
@@ -438,7 +458,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'hide',
],
helpString: 'Hides a chat message from the prompt.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'unhide',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'unhide',
callback: unhideMessageCallback,
unnamedArgumentList: [
new SlashCommandArgument(
@@ -447,7 +468,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'unhide',
],
helpString: 'Unhides a message from the prompt.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-disable',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'member-disable',
callback: disableGroupMemberCallback,
aliases: ['disable', 'disablemember', 'memberdisable'],
unnamedArgumentList: [
@@ -457,7 +479,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-disab
],
helpString: 'Disables a group member from being drafted for replies.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-enable',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'member-enable',
aliases: ['enable', 'enablemember', 'memberenable'],
callback: enableGroupMemberCallback,
unnamedArgumentList: [
@@ -467,7 +490,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-enabl
],
helpString: 'Enables a group member to be drafted for replies.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-add',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'member-add',
callback: addGroupMemberCallback,
aliases: ['addmember', 'memberadd'],
unnamedArgumentList: [
@@ -489,7 +513,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-add',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-remove',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'member-remove',
callback: removeGroupMemberCallback,
aliases: ['removemember', 'memberremove'],
unnamedArgumentList: [
@@ -512,7 +537,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-remov
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-up',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'member-up',
callback: moveGroupMemberUpCallback,
aliases: ['upmember', 'memberup'],
unnamedArgumentList: [
@@ -522,7 +548,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-up',
],
helpString: 'Moves a group member up in the group chat list.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-down',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'member-down',
callback: moveGroupMemberDownCallback,
aliases: ['downmember', 'memberdown'],
unnamedArgumentList: [
@@ -532,7 +559,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-down'
],
helpString: 'Moves a group member down in the group chat list.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'peek',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'peek',
callback: peekCallback,
unnamedArgumentList: [
new SlashCommandArgument(
@@ -558,7 +586,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'peek',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'delswipe',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'delswipe',
callback: deleteSwipeCallback,
aliases: ['swipedel'],
unnamedArgumentList: [
@@ -585,7 +614,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'delswipe',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'echo',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'echo',
callback: echoCallback,
returns: 'the text',
namedArgumentList: [
@@ -615,7 +645,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'echo',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'gen',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'gen',
callback: generateCallback,
returns: 'generated text',
namedArgumentList: [
@@ -646,7 +677,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'gen',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'genraw',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'genraw',
callback: generateRawCallback,
returns: 'generated text',
namedArgumentList: [
@@ -692,7 +724,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'genraw',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'addswipe',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'addswipe',
callback: addSwipeCallback,
aliases: ['swipeadd'],
unnamedArgumentList: [
@@ -702,10 +735,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'addswipe',
],
helpString: 'Adds a swipe to the last chat message.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'abort',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'abort',
callback: abortCallback,
namedArgumentList: [
- SlashCommandNamedArgument.fromProps({ name: 'quiet',
+ SlashCommandNamedArgument.fromProps({
+ name: 'quiet',
description: 'Whether to suppress the toast message notifying about the /abort call.',
typeList: [ARGUMENT_TYPE.BOOLEAN],
defaultValue: 'true',
@@ -713,13 +748,15 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'abort',
}),
],
unnamedArgumentList: [
- SlashCommandArgument.fromProps({ description: 'The reason for aborting command execution. Shown when quiet=false',
+ SlashCommandArgument.fromProps({
+ description: 'The reason for aborting command execution. Shown when quiet=false',
typeList: [ARGUMENT_TYPE.STRING],
}),
],
helpString: 'Aborts the slash command batch execution.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'fuzzy',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'fuzzy',
callback: fuzzyCallback,
returns: 'first matching item',
namedArgumentList: [
@@ -758,7 +795,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'fuzzy',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'pass',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'pass',
callback: (_, arg) => arg,
returns: 'the provided value',
unnamedArgumentList: [
@@ -779,7 +817,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'pass',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'delay',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'delay',
callback: delayCallback,
aliases: ['wait', 'sleep'],
unnamedArgumentList: [
@@ -801,7 +840,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'delay',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'input',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'input',
aliases: ['prompt'],
callback: inputCallback,
returns: 'user input',
@@ -834,7 +874,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'input',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'run',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'run',
aliases: ['call', 'exec'],
callback: runCallback,
returns: 'result of the executed closure of QR',
@@ -855,7 +896,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'run',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'messages',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'messages',
callback: getMessagesCallback,
aliases: ['message'],
namedArgumentList: [
@@ -866,7 +908,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'messages',
'hidden', 'include hidden messages', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', ['off', 'on'],
),
new SlashCommandNamedArgument(
- 'role', 'filter messages by role' , [ARGUMENT_TYPE.STRING], false, false, null, ['system', 'assistant', 'user'],
+ 'role', 'filter messages by role', [ARGUMENT_TYPE.STRING], false, false, null, ['system', 'assistant', 'user'],
),
],
unnamedArgumentList: [
@@ -900,7 +942,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'messages',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'setinput',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'setinput',
callback: setInputCallback,
unnamedArgumentList: [
new SlashCommandArgument(
@@ -921,7 +964,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'setinput',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'popup',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'popup',
callback: popupCallback,
returns: 'popup text',
namedArgumentList: [
@@ -955,7 +999,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'popup',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'buttons',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'buttons',
callback: buttonsCallback,
returns: 'clicked button label',
namedArgumentList: [
@@ -983,7 +1028,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'buttons',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trimtokens',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'trimtokens',
callback: trimTokensCallback,
returns: 'trimmed text',
namedArgumentList: [
@@ -1013,7 +1059,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trimtokens',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trimstart',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'trimstart',
callback: trimStartCallback,
returns: 'trimmed text',
unnamedArgumentList: [
@@ -1035,7 +1082,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trimstart',
`,
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trimend',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'trimend',
callback: trimEndCallback,
returns: 'trimmed text',
unnamedArgumentList: [
@@ -1045,7 +1093,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trimend',
],
helpString: 'Trims the text to the end of the last full sentence.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'inject',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'inject',
callback: injectCallback,
namedArgumentList: [
new SlashCommandNamedArgument(
@@ -1071,15 +1120,18 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'inject',
],
helpString: 'Injects a text into the LLM prompt for the current chat. Requires a unique injection ID. Positions: "before" main prompt, "after" main prompt, in-"chat" (default: after). Depth: injection depth for the prompt (default: 4). Role: role for in-chat injections (default: system). Scan: include injection content into World Info scans (default: false).',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'listinjects',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'listinjects',
callback: listInjectsCallback,
helpString: 'Lists all script injections for the current chat.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'flushinjects',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'flushinjects',
callback: flushInjectsCallback,
helpString: 'Removes all script injections for the current chat.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'tokens',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'tokens',
callback: (_, text) => getTokenCountAsync(text),
returns: 'number of tokens',
unnamedArgumentList: [
@@ -1089,7 +1141,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'tokens',
],
helpString: 'Counts the number of tokens in the provided text.',
}));
-SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'model',
+SlashCommandParser.addCommandObject(SlashCommand.fromProps({
+ name: 'model',
callback: modelCallback,
returns: 'current model',
unnamedArgumentList: [
@@ -1216,7 +1269,7 @@ export function processChatSlashCommands() {
}
function setInputCallback(_, value) {
- $('#send_textarea').val(value || '')[0].dispatchEvent(new Event('input', { bubbles:true }));
+ $('#send_textarea').val(value || '')[0].dispatchEvent(new Event('input', { bubbles: true }));
return value;
}
@@ -1410,7 +1463,7 @@ async function runCallback(args, name) {
throw new Error(`"${name}" is not callable.`);
}
closure.scope.parent = scope;
- closure.argumentList.forEach(arg=>{
+ closure.argumentList.forEach(arg => {
if (Object.keys(args).includes(arg.name)) {
const providedArg = new SlashCommandNamedArgumentAssignment();
providedArg.name = arg.name;
@@ -1559,7 +1612,7 @@ async function generateRawCallback(args, value) {
}
// Prevent generate recursion
- $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles:true }));
+ $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true }));
const lock = isTrueBoolean(args?.lock);
const as = args?.as || 'system';
const quietToLoud = as === 'char';
@@ -1589,7 +1642,7 @@ async function generateCallback(args, value) {
}
// Prevent generate recursion
- $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles:true }));
+ $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true }));
const lock = isTrueBoolean(args?.lock);
const as = args?.as || 'system';
const quietToLoud = as === 'char';
@@ -1725,7 +1778,7 @@ async function deleteSwipeCallback(_, arg) {
async function askCharacter(_, text) {
// Prevent generate recursion
- $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles:true }));
+ $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true }));
// Not supported in group chats
// TODO: Maybe support group chats?
@@ -2036,7 +2089,7 @@ async function triggerGenerationCallback(args, value) {
}
// Prevent generate recursion
- $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles:true }));
+ $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true }));
let chid = undefined;
@@ -2202,7 +2255,7 @@ function continueChatCallback(_, prompt) {
}
// Prevent infinite recursion
- $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles:true }));
+ $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true }));
$('#option_continue').trigger('click', { fromSlashCommand: true, additionalPrompt: prompt });
}, 1);
@@ -2210,7 +2263,7 @@ function continueChatCallback(_, prompt) {
}
export async function generateSystemMessage(_, prompt) {
- $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles:true }));
+ $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true }));
if (!prompt) {
console.warn('WARN: No prompt provided for /sysgen command');
@@ -2744,7 +2797,7 @@ export async function executeSlashCommandsOnChatInput(text, options = {}) {
if (options.clearChatInput) {
ta.value = '';
- ta.dispatchEvent(new Event('input', { bubbles:true }));
+ ta.dispatchEvent(new Event('input', { bubbles: true }));
}
document.querySelector('#send_textarea').style.setProperty('--prog', '0%');
@@ -2759,7 +2812,7 @@ export async function executeSlashCommandsOnChatInput(text, options = {}) {
commandsFromChatInputAbortController = new SlashCommandAbortController();
result = await executeSlashCommandsWithOptions(text, {
abortController: commandsFromChatInputAbortController,
- onProgress: (done, total)=>ta.style.setProperty('--prog', `${done / total * 100}%`),
+ onProgress: (done, total) => ta.style.setProperty('--prog', `${done / total * 100}%`),
});
if (commandsFromChatInputAbortController.signal.aborted) {
document.querySelector('#form_sheld').classList.add('script_aborted');
@@ -2775,7 +2828,7 @@ export async function executeSlashCommandsOnChatInput(text, options = {}) {
toastr.error(e.message);
}
} finally {
- delay(1000).then(()=>clearCommandProgressDebounced());
+ delay(1000).then(() => clearCommandProgressDebounced());
commandsFromChatInputAbortController = null;
deactivateScriptButtons();
@@ -2821,7 +2874,7 @@ async function executeSlashCommandsWithOptions(text, options = {}) {
toastr.error(
`${toast}${clickHint}`,
'SlashCommandParserError',
- { escapeHtml:false, timeOut: 10000, onclick:()=>callPopup(toast, 'text') },
+ { escapeHtml: false, timeOut: 10000, onclick: () => callPopup(toast, 'text') },
);
const result = new SlashCommandClosureResult();
return result;
@@ -2878,11 +2931,25 @@ async function executeSlashCommands(text, handleParserErrors = true, scope = nul
* @param {Boolean} isFloating Whether to show the auto complete as a floating window (e.g., large QR editor)
*/
export async function setSlashCommandAutoComplete(textarea, isFloating = false) {
+ function canUseNegativeLookbehind() {
+ try {
+ new RegExp('(? ac.text[0] == '/',
- async(text, index) => await parser.getNameAt(text, index),
+ async (text, index) => await parser.getNameAt(text, index),
isFloating,
);
}
diff --git a/public/scripts/slash-commands/SlashCommandParser.js b/public/scripts/slash-commands/SlashCommandParser.js
index 171a38491..9b839ca23 100644
--- a/public/scripts/slash-commands/SlashCommandParser.js
+++ b/public/scripts/slash-commands/SlashCommandParser.js
@@ -109,7 +109,7 @@ export class SlashCommandParser {
return this.text[this.index];
}
get endOfText() {
- return this.index >= this.text.length || /^\s+$/.test(this.ahead);
+ return this.index >= this.text.length || (/\s/.test(this.char) && /^\s+$/.test(this.ahead));
}
diff --git a/public/scripts/utils.js b/public/scripts/utils.js
index d62310b3c..63539513a 100644
--- a/public/scripts/utils.js
+++ b/public/scripts/utils.js
@@ -1341,11 +1341,7 @@ export async function extractTextFromHTML(blob, textSelector = 'body') {
*/
export async function extractTextFromMarkdown(blob) {
const markdown = await blob.text();
- const converter = new showdown.Converter();
- const html = converter.makeHtml(markdown);
- const domParser = new DOMParser();
- const document = domParser.parseFromString(DOMPurify.sanitize(html), 'text/html');
- const text = postProcessText(document.body.textContent, false);
+ const text = postProcessText(markdown, false);
return text;
}
@@ -1629,14 +1625,30 @@ export function highlightRegex(regexStr) {
regexStr = escapeHtml(regexStr);
// Patterns that we want to highlight only if they are not escaped
- const patterns = {
- brackets: /(? {
diff --git a/public/scripts/world-info.js b/public/scripts/world-info.js
index 10a9cc47e..256821b3f 100644
--- a/public/scripts/world-info.js
+++ b/public/scripts/world-info.js
@@ -186,7 +186,7 @@ class WorldInfoBuffer {
result += '\n' + this.#recurseBuffer.join('\n');
}
- return this.#transformString(result, entry);
+ return result;
}
/**
@@ -204,6 +204,7 @@ class WorldInfoBuffer {
}
// Otherwise we do normal matching of plaintext with the chosen entry settings
+ haystack = this.#transformString(haystack, entry);
const transformedString = this.#transformString(needle, entry);
const matchWholeWords = entry.matchWholeWords ?? world_info_match_whole_words;
diff --git a/public/style.css b/public/style.css
index e7ceb3208..55dbcaeca 100644
--- a/public/style.css
+++ b/public/style.css
@@ -693,23 +693,35 @@ body .panelControlBar {
#send_but {
visibility: hidden;
}
- #rightSendForm > div:not(.mes_send).stscript_btn {
- &.stscript_pause, &.stscript_stop {
+
+ #rightSendForm>div:not(.mes_send).stscript_btn {
+
+ &.stscript_pause,
+ &.stscript_stop {
display: flex;
}
}
+
&.script_paused {
- #rightSendForm > div:not(.mes_send).stscript_btn {
+ #rightSendForm>div:not(.mes_send).stscript_btn {
&.stscript_pause {
display: none;
}
+
&.stscript_continue {
display: flex;
}
}
}
}
-#rightSendForm > div:not(.mes_send) {
+
+@supports not selector(&) {
+ .stscript_btn {
+ display: none;
+ }
+}
+
+#rightSendForm>div:not(.mes_send) {
&.stscript_btn {
padding-right: 2px;
place-self: center;
@@ -717,16 +729,20 @@ body .panelControlBar {
transition: 0.3s;
opacity: 1;
display: none;
- &.stscript_pause > .fa-solid {
+
+ &.stscript_pause>.fa-solid {
background-color: rgb(146, 190, 252);
}
- &.stscript_continue > .fa-solid {
+
+ &.stscript_continue>.fa-solid {
background-color: rgb(146, 190, 252);
}
- &.stscript_stop > .fa-solid {
+
+ &.stscript_stop>.fa-solid {
background-color: rgb(215, 136, 114);
}
- > .fa-solid {
+
+ >.fa-solid {
--toastInfoColor: #2F96B4;
--progColor: rgba(0, 128, 0, 0.839);
border-radius: 35%;
@@ -740,8 +756,7 @@ body .panelControlBar {
align-items: center;
box-shadow:
0 0 0 var(--progColor),
- 0 0 0 var(--progColor)
- ;
+ 0 0 0 var(--progColor);
}
}
}
@@ -871,7 +886,7 @@ body .panelControlBar {
position: relative;
}
-#chat .mes.selected{
+#chat .mes.selected {
/* background-color: rgb(from var(--SmartThemeQuoteColor) r g b / .5); */
background-color: rgb(102, 0, 0);
}
@@ -1140,24 +1155,27 @@ select {
--prog: 0%;
--progDone: 0;
border-top: var(--progWidth) solid var(--progColor);
- clip-path: polygon(
- 0% calc(var(--progDone) * var(--progWidthClip)),
- var(--prog) calc(var(--progDone) * var(--progWidthClip)),
- var(--prog) var(--progWidthClip),
- 100% var(--progWidthClip),
- 100% 100%,
- 0% 100%
- );
+ clip-path: polygon(0% calc(var(--progDone) * var(--progWidthClip)),
+ var(--prog) calc(var(--progDone) * var(--progWidthClip)),
+ var(--prog) var(--progWidthClip),
+ 100% var(--progWidthClip),
+ 100% 100%,
+ 0% 100%);
transition: clip-path 200ms;
}
+
@keyframes script_progress_pulse {
- 0%, 100% {
+
+ 0%,
+ 100% {
border-top-color: var(--progColor);
}
+
50% {
border-top-color: var(--progFlashColor);
}
}
+
#form_sheld.isExecutingCommandsFromChatInput.script_paused #send_textarea {
animation-name: script_progress_pulse;
animation-duration: 1500ms;
@@ -1169,9 +1187,11 @@ select {
#form_sheld.script_success #send_textarea {
border-top-color: var(--progSuccessColor);
}
+
#form_sheld.script_error #send_textarea {
border-top-color: var(--progErrorColor);
}
+
#form_sheld.script_aborted #send_textarea {
border-top-color: var(--progAbortedColor);
}
@@ -1193,17 +1213,20 @@ select {
--direction: row;
left: 0;
right: 0;
+
&:before {
content: "";
flex: 0 1 calc(var(--targetOffset) * 1px);
display: block;
pointer-events: none;
}
+
.autoComplete {
flex: 0 0 auto;
width: 50vw;
pointer-events: all;
}
+
&:after {
content: "";
flex: 1 1 0;
@@ -1233,11 +1256,13 @@ select {
flex: 0 1 calc(var(--targetOffset) * 1px - 5vh);
display: block;
}
+
.autoComplete-details {
flex: 0 0 auto;
max-height: 80vh;
pointer-events: all;
}
+
&:after {
content: "";
flex: 1 1 0;
@@ -1248,35 +1273,42 @@ select {
flex-direction: row;
left: 0;
right: 0;
+
.autoComplete-details {
max-height: unset;
width: 25vw;
}
+
&.left {
&:before {
flex: 0 1 calc(var(--targetOffset) * 1px - 25vw);
}
+
&:after {
flex: 1 0 auto;
max-width: 50vw;
}
}
+
&.right {
&:before {
flex: 0 0 calc(var(--targetOffset) * 1px + 50vw);
}
}
+
&.full {
&:before {
content: "";
flex: 0 1 calc(var(--targetOffset) * 1px);
display: block;
}
+
.autoComplete-details {
flex: 0 0 auto;
max-width: 50vw;
width: unset;
}
+
&:after {
content: "";
flex: 1 1 0;
@@ -1311,6 +1343,7 @@ body[data-stscript-style="dark"] {
--ac-style-color-currentParenthesis: rgba(195 118 210 / 1);
--ac-style-color-comment: rgba(122 151 90 / 1);
}
+
body[data-stscript-style="light"] {
--ac-style-color-border: rgba(200 200 200 / 1);
--ac-style-color-background: rgba(248 248 248 / 1);
@@ -1331,6 +1364,7 @@ body[data-stscript-style="light"] {
--ac-style-color-currentParenthesis: rgba(195 118 210 / 1);
--ac-style-color-comment: rgba(70 126 26 / 1);
}
+
body[data-stscript-style="theme"] {
--ac-style-color-border: var(--SmartThemeBorderColor);
--ac-style-color-background: var(--SmartThemeBlurTintColor);
@@ -1350,10 +1384,13 @@ body[data-stscript-style="theme"] {
--ac-style-color-currentParenthesis: rgba(195 118 210 / 1);
--ac-style-color-comment: rgba(122 151 90 / 1);
}
+
body {
--ac-font-scale: 0.8;
}
-.autoComplete, .autoComplete-details {
+
+.autoComplete,
+.autoComplete-details {
--ac-color-border: var(--ac-style-color-border, rgba(69 69 69 / 1));
--ac-color-background: var(--ac-style-color-background, rgba(32 32 32 / 1));
--ac-color-text: var(--ac-style-color-text, rgba(204 204 204 / 1));
@@ -1394,47 +1431,121 @@ body {
line-height: 1.2;
text-align: left;
z-index: 10000;
- * { text-shadow: none; }
+
+ * {
+ text-shadow: none;
+ }
}
+
body[data-stscript-style] .autoComplete [data-option-type] {
- &[data-option-type="enum"] .type { color: var(--ac-color-string); }
- &[data-option-type="command"] .type { color: var(--ac-color-cmd); }
- &[data-option-type="namedArgument"] .type { color: var(--ac-color-argName); }
- &[data-option-type="variable"] .type { color: var(--ac-color-punctuationL1); }
- &[data-option-type="qr"] .type { color: var(--ac-color-variable); }
- &[data-option-type="macro"] .type { color: var(--ac-color-variableLanguage); }
+ &[data-option-type="enum"] .type {
+ color: var(--ac-color-string);
+ }
+
+ &[data-option-type="command"] .type {
+ color: var(--ac-color-cmd);
+ }
+
+ &[data-option-type="namedArgument"] .type {
+ color: var(--ac-color-argName);
+ }
+
+ &[data-option-type="variable"] .type {
+ color: var(--ac-color-punctuationL1);
+ }
+
+ &[data-option-type="qr"] .type {
+ color: var(--ac-color-variable);
+ }
+
+ &[data-option-type="macro"] .type {
+ color: var(--ac-color-variableLanguage);
+ }
}
+
body[data-stscript-style] .hljs.language-stscript {
- * { text-shadow: none !important; }
+ * {
+ text-shadow: none !important;
+ }
+
text-shadow: none !important;
background-color: var(--ac-style-color-background);
color: var(--ac-style-color-text);
- .hljs-title.function_ { color: var(--ac-style-color-cmd); }
- .hljs-title.function_.invoke__ { color: var(--ac-style-color-cmd); }
- .hljs-string { color: var(--ac-style-color-string); }
- .hljs-number { color: var(--ac-style-color-number); }
- .hljs-variable { color: var(--ac-style-color-variable); }
- .hljs-variable.language_ { color: var(--ac-style-color-variableLanguage); }
- .hljs-property { color: var(--ac-style-color-argName); }
- .hljs-punctuation { color: var(--ac-style-color-punctuation); }
- .hljs-keyword { color: var(--ac-style-color-variableLanguage); }
- .hljs-comment { color: var(--ac-style-color-comment); }
- .hljs-abort { color: var(--ac-style-color-abort, #e38e23); }
+ .hljs-title.function_ {
+ color: var(--ac-style-color-cmd);
+ }
+
+ .hljs-title.function_.invoke__ {
+ color: var(--ac-style-color-cmd);
+ }
+
+ .hljs-string {
+ color: var(--ac-style-color-string);
+ }
+
+ .hljs-number {
+ color: var(--ac-style-color-number);
+ }
+
+ .hljs-variable {
+ color: var(--ac-style-color-variable);
+ }
+
+ .hljs-variable.language_ {
+ color: var(--ac-style-color-variableLanguage);
+ }
+
+ .hljs-property {
+ color: var(--ac-style-color-argName);
+ }
+
+ .hljs-punctuation {
+ color: var(--ac-style-color-punctuation);
+ }
+
+ .hljs-keyword {
+ color: var(--ac-style-color-variableLanguage);
+ }
+
+ .hljs-comment {
+ color: var(--ac-style-color-comment);
+ }
+
+ .hljs-abort {
+ color: var(--ac-style-color-abort, #e38e23);
+ }
.hljs-closure {
- > .hljs-punctuation { color: var(--ac-style-color-punctuation); }
+ >.hljs-punctuation {
+ color: var(--ac-style-color-punctuation);
+ }
+
.hljs-closure {
- > .hljs-punctuation { color: var(--ac-style-color-punctuationL1); }
+ >.hljs-punctuation {
+ color: var(--ac-style-color-punctuationL1);
+ }
+
.hljs-closure {
- > .hljs-punctuation { color: var(--ac-style-color-punctuationL2); }
+ >.hljs-punctuation {
+ color: var(--ac-style-color-punctuationL2);
+ }
+
.hljs-closure {
- > .hljs-punctuation { color: var(--ac-style-color-punctuation); }
+ >.hljs-punctuation {
+ color: var(--ac-style-color-punctuation);
+ }
+
.hljs-closure {
- > .hljs-punctuation { color: var(--ac-style-color-punctuationL1); }
+ >.hljs-punctuation {
+ color: var(--ac-style-color-punctuationL1);
+ }
+
.hljs-closure {
- > .hljs-punctuation { color: var(--ac-style-color-punctuationL2); }
+ >.hljs-punctuation {
+ color: var(--ac-style-color-punctuationL2);
+ }
}
}
}
@@ -1450,44 +1561,52 @@ body[data-stscript-style] .hljs.language-stscript {
align-items: center;
max-height: calc(95vh - var(--bottom));
container-type: inline-size;
- > .item {
+
+ >.item {
cursor: pointer;
padding: 3px;
text-shadow: none;
display: flex;
gap: 0.5em;
display: contents;
+
@container (max-width: 80em) {
.specs {
grid-column: 2 / 4;
}
- > .help {
+
+ >.help {
grid-column: 2 / 4;
padding-left: 1em;
opacity: 0.75;
height: auto;
}
}
+
&.blank {
display: block;
grid-column: 1 / 4;
}
- &:hover > * {
+
+ &:hover>* {
background-color: var(--ac-color-hoveredBackground);
color: var(--ac-color-hoveredText);
}
- &.selected > * {
+
+ &.selected>* {
background-color: var(--ac-color-selectedBackground);
color: var(--ac-color-selectedText);
}
- > * {
+
+ >* {
height: 100%;
}
- > *+* {
+
+ >*+* {
padding-left: 0.5em;
}
- > .type {
+ >.type {
flex: 0 0 auto;
display: inline-flex;
justify-content: center;
@@ -1501,230 +1620,291 @@ body[data-stscript-style] .hljs.language-stscript {
/* &:before { content: "["; }
&:after { content: "]"; } */
}
- > .specs {
+
+ >.specs {
align-items: flex-start;
- > .name {
- > .matched {
+
+ >.name {
+ >.matched {
background-color: var(--ac-color-matchedBackground);
color: var(--ac-color-matchedText);
font-weight: bold;
}
}
- > .body {
+
+ >.body {
flex-wrap: wrap;
column-gap: 0.5em;
- > .arguments {
+
+ >.arguments {
display: contents;
height: 100%;
}
}
}
- > .help {
+
+ >.help {
height: 100%;
- > .helpContent {
+
+ >.helpContent {
text-overflow: ellipsis;
overflow: hidden;
- font-size: 0.9em;white-space: nowrap;
+ font-size: 0.9em;
+ white-space: nowrap;
line-height: 1.2;
max-height: 1.2em;
display: block;
- > * {
+
+ >* {
display: contents;
}
}
}
}
}
+
.autoComplete-details {
display: flex;
flex-direction: column;
gap: 0.5em;
- > .specs {
+
+ >.specs {
cursor: default;
flex-direction: column;
padding: 0.25em 0.25em 0.5em 0.25em;
border-bottom: 1px solid var(--ac-color-border);
- > .name {
+
+ >.name {
font-weight: bold;
color: var(--ac-color-text);
cursor: help;
+
&:hover {
text-decoration: 1px dotted underline;
}
}
- > .body {
+
+ >.body {
flex-direction: column;
gap: 0.5em;
- > .arguments {
+
+ >.arguments {
margin: 0;
padding-left: 1.25em;
- > .argumentItem::marker {
+
+ >.argumentItem::marker {
color: color-mix(in srgb, var(--ac-color-text), var(--ac-style-color-background));
}
.argumentSpec {
display: flex;
gap: 0.5em;
+
.argument-default {
&:before {
content: " = ";
color: var(--ac-color-text);
}
+
color: var(--ac-color-string);
}
}
.argument {
cursor: help;
+
&:hover:not(:has(.argument-name:hover, .argument-types:hover, .argument-enums:hover)) {
text-decoration: 1px dotted underline;
}
}
+
.argument-name,
.argument-types,
.argument-enums,
- .argument-default
- {
+ .argument-default {
cursor: help;
+
&:hover {
text-decoration: 1px dotted underline;
}
}
- .argument.optional + .argument-description:before,
- .argumentSpec:has(.argument.optional) + .argument-description:before
- {
+ .argument.optional+.argument-description:before,
+ .argumentSpec:has(.argument.optional)+.argument-description:before {
content: "(optional) ";
color: var(--ac-color-text);
opacity: 0.5;
}
+
.argument-description {
margin-left: 0.5em;
font-family: var(--mainFontFamily);
font-size: 0.9em;
}
}
+
.returns {
cursor: help;
+
&:hover {
text-decoration: 1px dotted underline;
}
}
}
}
- > .help {
+
+ >.help {
padding: 0 0.5em 0.5em 0.5em;
+
div {
margin-block-end: 1em;
}
+
ul {
margin: 0;
padding-left: 1.5em;
}
+
pre {
margin: 0;
- > code {
+
+ >code {
display: block;
padding: 0;
}
}
}
- > .aliases {
+
+ >.aliases {
padding: 0 0.5em 0.5em 0.5em;
- &:before { content: '(alias: '; }
- > .alias {
- font-family: monospace;
- &+.alias:before { content: ', '; }
+
+ &:before {
+ content: '(alias: ';
+ }
+
+ >.alias {
+ font-family: monospace;
+
+ &+.alias:before {
+ content: ', ';
+ }
+ }
+
+ &:after {
+ content: ')';
}
- &:after { content: ')'; }
}
}
-.autoComplete > .item, .autoComplete-details {
- > .specs {
+.autoComplete>.item,
+.autoComplete-details {
+ >.specs {
display: flex;
gap: 0.5em;
- > .name {
+
+ >.name {
font-family: monospace;
white-space: nowrap;
/* color: var(--ac-color-text); */
}
- > .body {
+
+ >.body {
display: flex;
- > .arguments {
+
+ >.arguments {
font-family: monospace;
+
.argument {
white-space: nowrap;
+
&.namedArgument {
&:before {
content: "[";
color: var(--ac-color-text);
}
+
&:after {
content: "]";
color: var(--ac-color-text);
}
+
&.optional:after {
content: "]?";
color: var(--ac-color-text);
}
- > .argument-name {
+
+ >.argument-name {
color: var(--ac-color-argName);
}
}
+
&.unnamedArgument {
&:before {
content: "(";
color: var(--ac-color-text);
}
+
&.multiple:before {
content: "...(";
color: var(--ac-color-text);
}
+
&:after {
content: ")";
color: var(--ac-color-text);
}
+
&.optional:after {
content: ")?";
color: var(--ac-color-text);
}
}
- > .argument-name + .argument-types:before {
+
+ >.argument-name+.argument-types:before {
content: "=";
color: var(--ac-color-text);
}
- > .argument-types {
+
+ >.argument-types {
color: var(--ac-color-type);
word-break: break-all;
white-space: break-spaces;
- > .argument-type + .argument-type:before {
+
+ >.argument-type+.argument-type:before {
content: "|";
color: var(--ac-color-text);
- };
+ }
+
+ ;
}
- > .argument-types + .argument-enums,
- > .argument-name + .argument-enums
- {
+
+ >.argument-types+.argument-enums,
+ >.argument-name+.argument-enums {
&:before {
content: "=";
color: var(--ac-color-text);
}
}
- > .argument-enums {
+
+ >.argument-enums {
color: var(--ac-color-string);
word-break: break-all;
white-space: break-spaces;
- > .argument-enum + .argument-enum:before {
+
+ >.argument-enum+.argument-enum:before {
content: "|";
color: var(--ac-color-text);
- };
+ }
+
+ ;
}
}
}
- > .returns {
+
+ >.returns {
font-family: monospace;
color: var(--ac-color-text);
+
&:before {
content: "=> ";
color: var(--ac-color-symbol);
@@ -1733,56 +1913,68 @@ body[data-stscript-style] .hljs.language-stscript {
}
}
}
+
@media screen and (max-width: 1000px) {
.autoComplete-wrap {
left: 1vw;
right: 1vw;
}
+
.autoComplete-detailsWrap:not(.full) {
left: 50vw;
}
}
+
.slashCommandBrowser {
- > .search {
+ >.search {
display: flex;
gap: 1em;
align-items: baseline;
white-space: nowrap;
- > .searchLabel {
+
+ >.searchLabel {
flex: 1 1 auto;
display: flex;
gap: 0.5em;
align-items: baseline;
- > .searchInput {
+
+ >.searchInput {
flex: 1 1 auto;
}
}
- > .searchOptions {
+
+ >.searchOptions {
display: flex;
gap: 1em;
align-items: baseline;
}
}
- > .commandContainer {
+
+ >.commandContainer {
display: flex;
align-items: flex-start;
container-type: inline-size;
- > .autoComplete {
+
+ >.autoComplete {
flex: 1 1 auto;
max-height: unset;
- > .isFiltered {
+
+ >.isFiltered {
display: none;
}
+
.specs {
grid-column: 2 / 4;
}
+
.help {
grid-column: 2 / 4;
padding-left: 1em;
opacity: 0.75;
}
}
- > .autoComplete-detailsWrap {
+
+ >.autoComplete-detailsWrap {
flex: 0 0 auto;
align-self: stretch;
width: 30%;
@@ -1791,12 +1983,14 @@ body[data-stscript-style] .hljs.language-stscript {
&:before {
flex: 0 1 calc(var(--targetOffset) * 1px);
}
- > .autoComplete-details {
+
+ >.autoComplete-details {
max-height: 50vh;
}
}
+
@container (max-width: 1000px) {
- > .autoComplete-detailsWrap {
+ >.autoComplete-detailsWrap {
width: 50%;
max-width: unset;
position: absolute;
@@ -3371,38 +3565,46 @@ input[type="range"]::-webkit-slider-thumb {
--markerWidth: 15px;
container-type: inline-size;
container-name: doubleRangeContainer;
- > .doubleRangeInputContainer {
+
+ >.doubleRangeInputContainer {
flex: 0 0 50%;
overflow: hidden;
position: relative;
- > datalist {
+
+ >datalist {
display: flex;
flex-direction: row;
justify-content: space-between;
font-size: x-small;
- > option {
+
+ >option {
flex: 0 0 0;
width: 0;
display: flex;
justify-content: center;
}
}
+
@container doubleRangeContainer (max-width: 200px) {
- > datalist {
+ >datalist {
height: 2.5em;
}
- &:nth-child(1) > datalist > option {
+
+ &:nth-child(1)>datalist>option {
transform: rotate(-45deg);
transform-origin: bottom right;
}
- &:nth-child(2) > datalist > option {
+
+ &:nth-child(2)>datalist>option {
transform: rotate(45deg);
transform-origin: bottom left;
}
}
- > input::-webkit-slider-thumb {
+
+ >input::-webkit-slider-thumb {
z-index: 2;
}
+
&:after {
/* shifted to center to hide corners of the inset shadow */
--shift: 2px;
@@ -3422,34 +3624,42 @@ input[type="range"]::-webkit-slider-thumb {
background-color: var(--SmartThemeQuoteColor);
box-shadow: inset 0 0 2px black;
}
+
&:nth-child(1) {
--value: 0;
padding-left: 1em;
- > input {
+
+ >input {
direction: rtl;
position: relative;
padding-right: max(20px, 20%);
}
- > datalist {
+
+ >datalist {
direction: rtl;
padding-right: calc(var(--markerWidth)/2 + max(20px, 20%));
padding-left: calc(var(--markerWidth)/2 - 2px);
}
+
&:after {
right: -2px;
}
}
+
&:nth-child(2) {
--value: 0;
padding-right: 1em;
- > input {
+
+ >input {
position: relative;
padding-left: max(20px, 20%);
}
- > datalist {
+
+ >datalist {
padding-left: calc(var(--markerWidth)/2 + max(20px, 20%));
padding-right: calc(var(--markerWidth)/2 - 2px);
}
+
&:after {
left: -2px;
}
@@ -4278,6 +4488,7 @@ a {
#CustomCSS-textAreaBlock {
display: contents;
}
+
#customCSS {
flex: 1 1 auto;
}
@@ -4666,6 +4877,7 @@ body:not(.movingUI) .drawer-content.maximized {
backdrop-filter: blur(var(--SmartThemeBlurStrength));
background-color: var(--SmartThemeBlurTintColor);
padding: 5px;
+ border: 1px solid red;
}
.zoomed_avatar {
@@ -4683,12 +4895,13 @@ body:not(.movingUI) .drawer-content.maximized {
position: absolute;
height: auto;
max-height: 90vh !important;
- align-items: end;
+ align-items: start;
}
-.zoomed_avatar .dragClose {
+/*why were we force hiding the close button again..?*/
+/* .zoomed_avatar .dragClose {
display: none;
-}
+} */
.zoomed_avatar_container {
width: 100%;
@@ -4887,10 +5100,39 @@ body:not(.movingUI) .drawer-content.maximized {
}
/* CSS styles using a consistent pastel color palette */
-.regex-brackets { color: #FFB347; } /* Pastel Orange */
-.regex-special { color: #B0E0E6; } /* Powder Blue */
-.regex-quantifier { color: #DDA0DD; } /* Plum */
-.regex-operator { color: #FFB6C1; } /* Light Pink */
-.regex-flags { color: #98FB98; } /* Pale Green */
-.regex-delimiter { font-weight: bold; color: #FF6961; } /* Pastel Red */
-.regex-highlight { color: #FAF8F6; } /* Pastel White */
+.regex-brackets {
+ color: #FFB347;
+}
+
+/* Pastel Orange */
+.regex-special {
+ color: #B0E0E6;
+}
+
+/* Powder Blue */
+.regex-quantifier {
+ color: #DDA0DD;
+}
+
+/* Plum */
+.regex-operator {
+ color: #FFB6C1;
+}
+
+/* Light Pink */
+.regex-flags {
+ color: #98FB98;
+}
+
+/* Pale Green */
+.regex-delimiter {
+ font-weight: bold;
+ color: #FF6961;
+}
+
+/* Pastel Red */
+.regex-highlight {
+ color: #FAF8F6;
+}
+
+/* Pastel White */
\ No newline at end of file
diff --git a/src/endpoints/content-manager.js b/src/endpoints/content-manager.js
index c282dba36..f87520189 100644
--- a/src/endpoints/content-manager.js
+++ b/src/endpoints/content-manager.js
@@ -509,6 +509,40 @@ async function downloadGenericPng(url) {
return null;
}
+/**
+ * Parse Risu Realm URL to extract the UUID.
+ * @param {string} url Risu Realm URL
+ * @returns {string | null} UUID of the character
+ */
+function parseRisuUrl(url) {
+ // Example: https://realm.risuai.net/character/7adb0ed8d81855c820b3506980fb40f054ceef010ff0c4bab73730c0ebe92279
+ // or https://realm.risuai.net/character/7adb0ed8-d818-55c8-20b3-506980fb40f0
+ const pattern = /^https?:\/\/realm\.risuai\.net\/character\/([a-f0-9-]+)\/?$/i;
+ const match = url.match(pattern);
+ return match ? match[1] : null;
+}
+
+/**
+ * Download RisuAI character card
+ * @param {string} uuid UUID of the character
+ * @returns {Promise<{buffer: Buffer, fileName: string, fileType: string}>}
+ */
+async function downloadRisuCharacter(uuid) {
+ const result = await fetch(`https://realm.risuai.net/api/v1/download/png-v3/${uuid}?non_commercial=true`);
+
+ if (!result.ok) {
+ const text = await result.text();
+ console.log('RisuAI returned error', result.statusText, text);
+ throw new Error('Failed to download character');
+ }
+
+ const buffer = await result.buffer();
+ const fileName = `${sanitize(uuid)}.png`;
+ const fileType = 'image/png';
+
+ return { buffer, fileName, fileType };
+}
+
/**
* @param {String} url
* @returns {String | null } UUID of the character
@@ -563,6 +597,7 @@ router.post('/importURL', jsonParser, async (request, response) => {
const isJannnyContent = host.includes('janitorai');
const isPygmalionContent = host.includes('pygmalion.chat');
const isAICharacterCardsContent = host.includes('aicharactercards.com');
+ const isRisu = host.includes('realm.risuai.net');
const isGeneric = isHostWhitelisted(host);
if (isPygmalionContent) {
@@ -603,6 +638,14 @@ router.post('/importURL', jsonParser, async (request, response) => {
else {
return response.sendStatus(404);
}
+ } else if (isRisu) {
+ const uuid = parseRisuUrl(url);
+ if (!uuid) {
+ return response.sendStatus(404);
+ }
+
+ type = 'character';
+ result = await downloadRisuCharacter(uuid);
} else if (isGeneric) {
console.log('Downloading from generic url.');
type = 'character';