Merge branch 'staging' into ru-l10n

This commit is contained in:
Cohee
2024-05-20 21:45:02 +03:00
15 changed files with 966 additions and 288 deletions

35
package-lock.json generated
View File

@ -61,6 +61,9 @@
"@types/jquery": "^3.5.29", "@types/jquery": "^3.5.29",
"eslint": "^8.55.0", "eslint": "^8.55.0",
"jquery": "^3.6.4" "jquery": "^3.6.4"
},
"engines": {
"node": ">= 18"
} }
}, },
"node_modules/@aashutoshrathi/word-wrap": { "node_modules/@aashutoshrathi/word-wrap": {
@ -3885,7 +3888,6 @@
}, },
"node_modules/punycode": { "node_modules/punycode": {
"version": "2.3.1", "version": "2.3.1",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
@ -4435,8 +4437,15 @@
} }
}, },
"node_modules/tr46": { "node_modules/tr46": {
"version": "0.0.3", "version": "5.0.0",
"license": "MIT" "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": { "node_modules/truncate-utf8-bytes": {
"version": "1.0.2", "version": "1.0.2",
@ -4585,19 +4594,27 @@
} }
}, },
"node_modules/webidl-conversions": { "node_modules/webidl-conversions": {
"version": "3.0.1", "version": "7.0.0",
"license": "BSD-2-Clause" "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": { "node_modules/whatwg-fetch": {
"version": "3.6.18", "version": "3.6.18",
"license": "MIT" "license": "MIT"
}, },
"node_modules/whatwg-url": { "node_modules/whatwg-url": {
"version": "5.0.0", "version": "14.0.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
"integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
"dependencies": { "dependencies": {
"tr46": "~0.0.3", "tr46": "^5.0.0",
"webidl-conversions": "^3.0.0" "webidl-conversions": "^7.0.0"
},
"engines": {
"node": ">=18"
} }
}, },
"node_modules/which": { "node_modules/which": {

View File

@ -44,6 +44,9 @@
"yargs": "^17.7.1", "yargs": "^17.7.1",
"yauzl": "^2.10.0" "yauzl": "^2.10.0"
}, },
"engines": {
"node": ">= 18"
},
"overrides": { "overrides": {
"parse-bmfont-xml": { "parse-bmfont-xml": {
"xml2js": "^0.5.0" "xml2js": "^0.5.0"
@ -59,6 +62,9 @@
}, },
"@zeldafan0225/ai_horde": { "@zeldafan0225/ai_horde": {
"esbuild": "npm:dry-uninstall" "esbuild": "npm:dry-uninstall"
},
"node-fetch": {
"whatwg-url": "^14.0.0"
} }
}, },
"name": "sillytavern", "name": "sillytavern",

View File

@ -6279,11 +6279,11 @@
</div> </div>
<div id="zoomed_avatar_template" class="template_element"> <div id="zoomed_avatar_template" class="template_element">
<div class="zoomed_avatar"> <div class="zoomed_avatar">
<div class="zoomed_avatar_container">
<div class="panelControlBar flex-container"> <div class="panelControlBar flex-container">
<div class="fa-fw fa-solid fa-grip drag-grabber"></div> <div class="fa-fw fa-solid fa-grip drag-grabber"></div>
<div class="fa-fw fa-solid fa-circle-xmark dragClose" id="closeZoom"></div> <div class="fa-fw fa-solid fa-circle-xmark dragClose" id="closeZoom"></div>
</div> </div>
<div class="zoomed_avatar_container">
<img class="zoomed_avatar_img" src="" data-izoomify-url="" data-izoomify-magnify="1.8" data-izoomify-duration="300" alt=""> <img class="zoomed_avatar_img" src="" data-izoomify-url="" data-izoomify-magnify="1.8" data-izoomify-duration="300" alt="">
</div> </div>
</div> </div>

View File

@ -1547,6 +1547,13 @@ function getCharacterSource(chId = this_chid) {
return sourceUrl; 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 ''; return '';
} }
@ -5938,7 +5945,7 @@ export function changeMainAPI() {
getStatusHorde(); getStatusHorde();
getHordeModels(true); getHordeModels(true);
} }
validateDisabledSamplers() validateDisabledSamplers();
setupChatCompletionPromptManager(oai_settings); setupChatCompletionPromptManager(oai_settings);
forceCharacterEditorTokenize(); forceCharacterEditorTokenize();
} }
@ -6169,7 +6176,7 @@ export async function getSettings() {
firstRun = false; firstRun = false;
} }
} }
await validateDisabledSamplers() await validateDisabledSamplers();
settingsReady = true; settingsReady = true;
eventSource.emit(event_types.SETTINGS_LOADED); eventSource.emit(event_types.SETTINGS_LOADED);
} }
@ -10240,19 +10247,8 @@ jQuery(async function () {
if (power_user.zoomed_avatar_magnification) { if (power_user.zoomed_avatar_magnification) {
$('.zoomed_avatar_container').izoomify(); $('.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) => { $('.zoomed_avatar, .zoomed_avatar .dragClose').on('click touchend', (e) => {
if (e.target.closest('.dragClose')) { if (e.target.closest('.dragClose')) {
$(`.zoomed_avatar[forChar="${charname}"]`).fadeOut(animation_duration, () => { $(`.zoomed_avatar[forChar="${charname}"]`).fadeOut(animation_duration, () => {

View File

@ -436,8 +436,6 @@ const saveUserInputDebounced = debounce(saveUserInput);
// Make the DIV element draggable: // Make the DIV element draggable:
// THIRD UPDATE, prevent resize window breaks and smartly handle saving
export function dragElement(elmnt) { export function dragElement(elmnt) {
var hasBeenDraggedByUser = false; var hasBeenDraggedByUser = false;
var isMouseDown = false; var isMouseDown = false;
@ -479,8 +477,8 @@ export function dragElement(elmnt) {
} }
//console.debug(left + width, winWidth, hasBeenDraggedByUser, isMouseDown) //console.debug(left + width, winWidth, hasBeenDraggedByUser, isMouseDown)
const style = getComputedStyle(target); //use computed values because not all CSS are set by default const style = getComputedStyle(target); //use computed values because not all CSS are set by default
height = target.offsetHeight; height = parseInt(style.height) //target.offsetHeight;
width = target.offsetWidth; width = parseInt(style.width) //target.offsetWidth;
top = parseInt(style.top); top = parseInt(style.top);
left = parseInt(style.left); left = parseInt(style.left);
right = parseInt(style.right); right = parseInt(style.right);
@ -494,19 +492,20 @@ export function dragElement(elmnt) {
const topbarstyle = getComputedStyle(topbar); const topbarstyle = getComputedStyle(topbar);
topBarFirstX = parseInt(topbarstyle.marginInline); topBarFirstX = parseInt(topbarstyle.marginInline);
topBarLastY = parseInt(topbarstyle.height); topBarLastY = parseInt(topbarstyle.height);
/*
/*console.log(` console.log(`
Observer
winWidth: ${winWidth}, winHeight: ${winHeight} winWidth: ${winWidth}, winHeight: ${winHeight}
sheldWidth: ${sheldWidth} sheldWidth: sheldWidth
X: ${$(elmnt).css('left')} X: ${$(elmnt).css('left')}
Y: ${$(elmnt).css('top')} Y: ${$(elmnt).css('top')}
MaxX: ${maxX}, MaxY: ${maxY} MaxX: ${maxX}, MaxY: ${maxY}
height: ${height} height: ${height}
width: ${width} width: ${width}
Topbar 1st X: ${topBarFirstX} Topbar 1st X: ${topBarFirstX}
TopBar lastX: ${topBarLastX} TopBar lastX: topBarLastX
`);*/ `);
*/
//prepare an empty poweruser object for the item being altered if we don't have one already //prepare an empty poweruser object for the item being altered if we don't have one already
if (!power_user.movingUIState[elmntName]) { if (!power_user.movingUIState[elmntName]) {
@ -524,24 +523,38 @@ export function dragElement(elmnt) {
} }
//handle resizing //handle resizing
if (!hasBeenDraggedByUser && isMouseDown) { if (!hasBeenDraggedByUser && isMouseDown) { //if user is dragging the resize handle (not in header)
console.debug('saw resize, NOT header drag'); //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 //prevent resizing offscreen
if (top + elmnt.height() >= winHeight) { 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'); elmnt.css('height', winHeight - top - 1 + 'px');
} }
if (left + elmnt.width() >= winWidth) { 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'); elmnt.css('width', winWidth - left - 1 + 'px');
} }
//prevent resizing from top left into the top bar //prevent resizing from top left into the top bar
if (top < topBarLastY && maxX >= topBarFirstX && left <= topBarFirstX 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'); 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 // and will defaults to shrink to min value of 100px set in CSS file
elmnt.css('height', height); elmnt.css('height', height);
elmnt.css('width', width); elmnt.css('width', width);
/*
console.log(` /*console.log(`
elementDrag:
winWidth: ${winWidth}, winHeight: ${winHeight} winWidth: ${winWidth}, winHeight: ${winHeight}
sheldWidth: ${sheldWidth} sheldWidth: sheldWidth
X: ${$(elmnt).css('left')} X: ${$(elmnt).css('left')}
Y: ${$(elmnt).css('top')} Y: ${$(elmnt).css('top')}
MaxX: ${maxX}, MaxY: ${maxY} MaxX: ${maxX}, MaxY: ${maxY}
height: ${height} height: ${height}
width: ${width} width: ${width}
Topbar 1st X: ${topBarFirstX} Topbar 1st X: ${topBarFirstX}
TopBar lastX: ${topBarLastX} TopBar lastX: topBarLastX
`); `);*/
*/
return; return;
} }

View File

@ -73,6 +73,7 @@
* @property {string} [github_repo] - The gitHub repository associated with the character. * @property {string} [github_repo] - The gitHub repository associated with the character.
* @property {string} [source_url] - The source URL 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 {{full_path: string}} [chub] - The Chub-specific data associated with the character.
* @property {{source: string[]}} [risuai] - The RisuAI-specific data associated with the character.
*/ */
/** /**

View File

@ -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('<br>', '\n'); // Replace <br> 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 = `
<label for="gsvi_api_language">Text Language</label>
<select id="gsvi_api_language">`;
for (let language in this.languageLabels) {
if (this.languageLabels[language] == this.settings?.language) {
html += `<option value="${this.languageLabels[language]}" selected="selected">${language}</option>`;
continue;
}
html += `<option value="${this.languageLabels[language]}">${language}</option>`;
}
html += `
</select>
<label>GSVI Settings:</label><br/>
<label for="gsvi_tts_endpoint">Provider Endpoint:</label>
<input id="gsvi_tts_endpoint" type="text" class="text_pole" maxlength="250" value="${this.defaultSettings.provider_endpoint}"/>
<label for="gsvi_speed">Speed: <span id="gsvi_tts_speed_output">${this.defaultSettings.speed}</span></label>
<input id="gsvi_speed" type="range" value="${this.defaultSettings.speed}" min="0.5" max="2" step="0.01" />
<label for="gsvi_top_k">Top K: <span id="gsvi_top_k_output">${this.defaultSettings.top_k}</span></label>
<input id="gsvi_top_k" type="range" value="${this.defaultSettings.top_k}" min="0" max="100" step="1" />
<label for="gsvi_top_p">Top P: <span id="gsvi_top_p_output">${this.defaultSettings.top_p}</span></label>
<input id="gsvi_top_p" type="range" value="${this.defaultSettings.top_p}" min="0" max="1" step="0.01" />
<label for="gsvi_temperature">Temperature: <span id="gsvi_tts_temperature_output">${this.defaultSettings.temperature}</span></label>
<input id="gsvi_temperature" type="range" value="${this.defaultSettings.temperature}" min="0.01" max="1" step="0.01" />
<label for="gsvi_batch_size">Batch Size: <span id="gsvi_batch_size_output">${this.defaultSettings.batch_size}</span></label>
<input id="gsvi_batch_size" type="range" value="${this.defaultSettings.batch_size}" min="1" max="35" step="1" />
<label for="gsvi_tts_streaming" class="checkbox_label">
<input id="gsvi_tts_streaming" type="checkbox" ${this.defaultSettings.stream ? 'checked' : ''}/>
<span>Streaming</span>
</label>
<label for="gsvi_stream_chunk_size">Stream Chunk Size: <span id="gsvi_stream_chunk_size_output">${this.defaultSettings.stream_chunk_size}</span></label>
<input id="gsvi_stream_chunk_size" type="range" value="${this.defaultSettings.stream_chunk_size}" min="100" max="400" step="1" />
<p>
For more information, visit the
<a href="https://github.com/X-T-E-R/GPT-SoVITS-Inference" target="_blank">GSVI project page</a>.
</p>
`;
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);
}
}

View File

@ -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 { GSVITtsProvider } from './gsvi.js';
import { AllTalkTtsProvider } from './alltalk.js'; import { AllTalkTtsProvider } from './alltalk.js';
import { SpeechT5TtsProvider } from './speecht5.js'; import { SpeechT5TtsProvider } from './speecht5.js';
import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js'; import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
@ -74,6 +75,7 @@ const ttsProviders = {
ElevenLabs: ElevenLabsTtsProvider, ElevenLabs: ElevenLabsTtsProvider,
Silero: SileroTtsProvider, Silero: SileroTtsProvider,
XTTSv2: XTTSTtsProvider, XTTSv2: XTTSTtsProvider,
GSVI: GSVITtsProvider,
System: SystemTtsProvider, System: SystemTtsProvider,
Coqui: CoquiTtsProvider, Coqui: CoquiTtsProvider,
Edge: EdgeTtsProvider, Edge: EdgeTtsProvider,

View File

@ -1389,7 +1389,7 @@ async function applyTheme(name) {
} }
async function applyMovingUIPreset(name) { async function applyMovingUIPreset(name) {
resetMovablePanels('quiet'); await resetMovablePanels('quiet');
const movingUIPreset = movingUIPresets.find(x => x.name == name); const movingUIPreset = movingUIPresets.find(x => x.name == name);
if (!movingUIPreset) { if (!movingUIPreset) {
@ -1401,6 +1401,7 @@ async function applyMovingUIPreset(name) {
console.log('MovingUI Preset applied: ' + name); console.log('MovingUI Preset applied: ' + name);
loadMovingUIState(); loadMovingUIState();
saveSettingsDebounced()
} }
/** /**
@ -3789,15 +3790,18 @@ $(document).ready(() => {
browser_has_focus = false; browser_has_focus = false;
}); });
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'vn', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'vn',
callback: toggleWaifu, callback: toggleWaifu,
helpString: 'Swaps Visual Novel Mode On/Off', helpString: 'Swaps Visual Novel Mode On/Off',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'newchat', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'newchat',
callback: doNewChat, callback: doNewChat,
helpString: 'Start a new chat with the current character', helpString: 'Start a new chat with the current character',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'random', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'random',
callback: doRandomChat, callback: doRandomChat,
unnamedArgumentList: [ unnamedArgumentList: [
new SlashCommandArgument( 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.', 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, callback: doDelMode,
aliases: ['del'], aliases: ['del'],
unnamedArgumentList: [ unnamedArgumentList: [
@ -3816,7 +3821,8 @@ $(document).ready(() => {
], ],
helpString: 'Enter message deletion mode, and auto-deletes last N messages if numeric argument is provided.', 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, callback: doMesCut,
returns: 'the text of cut messages separated by a newline', returns: 'the text of cut messages separated by a newline',
unnamedArgumentList: [ unnamedArgumentList: [
@ -3842,16 +3848,19 @@ $(document).ready(() => {
`, `,
aliases: [], aliases: [],
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'resetpanels', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'resetpanels',
callback: doResetPanels, callback: doResetPanels,
helpString: 'resets UI panels to original state', helpString: 'resets UI panels to original state',
aliases: ['resetui'], aliases: ['resetui'],
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'bgcol', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'bgcol',
callback: setAvgBG, callback: setAvgBG,
helpString: ' WIP test of auto-bg avg coloring', helpString: ' WIP test of auto-bg avg coloring',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'theme', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'theme',
callback: setThemeCallback, callback: setThemeCallback,
unnamedArgumentList: [ unnamedArgumentList: [
new SlashCommandArgument( new SlashCommandArgument(
@ -3860,7 +3869,8 @@ $(document).ready(() => {
], ],
helpString: 'sets a UI theme by name', helpString: 'sets a UI theme by name',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'movingui', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'movingui',
callback: setmovingUIPreset, callback: setmovingUIPreset,
unnamedArgumentList: [ unnamedArgumentList: [
new SlashCommandArgument( new SlashCommandArgument(

View File

@ -73,7 +73,8 @@ 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);
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: '?', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: '?',
callback: helpCommandCallback, callback: helpCommandCallback,
aliases: ['help'], aliases: ['help'],
unnamedArgumentList: [new SlashCommandArgument( unnamedArgumentList: [new SlashCommandArgument(
@ -81,7 +82,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: '?',
)], )],
helpString: 'Get help on macros, chat formatting and commands.', helpString: 'Get help on macros, chat formatting and commands.',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'name', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'name',
callback: setNameCallback, callback: setNameCallback,
unnamedArgumentList: [ unnamedArgumentList: [
new SlashCommandArgument( new SlashCommandArgument(
@ -91,16 +93,19 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'name',
helpString: 'Sets user name and persona avatar (if set).', helpString: 'Sets user name and persona avatar (if set).',
aliases: ['persona'], aliases: ['persona'],
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sync', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'sync',
callback: syncCallback, callback: syncCallback,
helpString: 'Syncs the user persona in user-attributed messages in the current chat.', 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, callback: bindCallback,
aliases: ['bind'], aliases: ['bind'],
helpString: 'Locks/unlocks a persona (name and avatar) to the current chat', 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, callback: setBackgroundCallback,
aliases: ['background'], aliases: ['background'],
returns: 'the current background', returns: 'the current background',
@ -123,7 +128,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'bg',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sendas', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'sendas',
callback: sendMessageAs, callback: sendMessageAs,
namedArgumentList: [ namedArgumentList: [
new SlashCommandNamedArgument( new SlashCommandNamedArgument(
@ -161,7 +167,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sendas',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sys', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'sys',
callback: sendNarratorMessage, callback: sendNarratorMessage,
aliases: ['nar'], aliases: ['nar'],
namedArgumentList: [ namedArgumentList: [
@ -204,7 +211,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sys',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sysname', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'sysname',
callback: setNarratorName, callback: setNarratorName,
unnamedArgumentList: [ unnamedArgumentList: [
new SlashCommandArgument( 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.', 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, callback: sendCommentMessage,
namedArgumentList: [ namedArgumentList: [
new SlashCommandNamedArgument( new SlashCommandNamedArgument(
@ -257,22 +266,26 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'comment',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'single', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'single',
callback: setStoryModeCallback, callback: setStoryModeCallback,
aliases: ['story'], aliases: ['story'],
helpString: 'Sets the message style to single document mode without names or avatars visible.', 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, callback: setBubbleModeCallback,
aliases: ['bubbles'], aliases: ['bubbles'],
helpString: 'Sets the message style to bubble chat mode.', helpString: 'Sets the message style to bubble chat mode.',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'flat', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'flat',
callback: setFlatModeCallback, callback: setFlatModeCallback,
aliases: ['default'], aliases: ['default'],
helpString: 'Sets the message style to flat chat mode.', helpString: 'Sets the message style to flat chat mode.',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'continue', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'continue',
callback: continueChatCallback, callback: continueChatCallback,
aliases: ['cont'], aliases: ['cont'],
unnamedArgumentList: [ unnamedArgumentList: [
@ -299,7 +312,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'continue',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'go', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'go',
callback: goToCharacterCallback, callback: goToCharacterCallback,
unnamedArgumentList: [ unnamedArgumentList: [
new SlashCommandArgument( 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', helpString: 'Opens up a chat with the character or group by its name',
aliases: ['char'], aliases: ['char'],
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sysgen', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'sysgen',
callback: generateSystemMessage, callback: generateSystemMessage,
unnamedArgumentList: [ unnamedArgumentList: [
new SlashCommandArgument( new SlashCommandArgument(
@ -318,7 +333,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'sysgen',
], ],
helpString: 'Generates a system message using a specified prompt.', helpString: 'Generates a system message using a specified prompt.',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'ask', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'ask',
callback: askCharacter, callback: askCharacter,
unnamedArgumentList: [ unnamedArgumentList: [
new SlashCommandArgument( 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.', 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, callback: deleteMessagesByNameCallback,
namedArgumentList: [], namedArgumentList: [],
unnamedArgumentList: [ unnamedArgumentList: [
@ -353,7 +370,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'delname',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'send', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'send',
callback: sendUserMessageCallback, callback: sendUserMessageCallback,
namedArgumentList: [ namedArgumentList: [
new SlashCommandNamedArgument( new SlashCommandNamedArgument(
@ -408,7 +426,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'send',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trigger', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'trigger',
callback: triggerGenerationCallback, callback: triggerGenerationCallback,
namedArgumentList: [ namedArgumentList: [
new SlashCommandNamedArgument( new SlashCommandNamedArgument(
@ -429,7 +448,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trigger',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'hide', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'hide',
callback: hideMessageCallback, callback: hideMessageCallback,
unnamedArgumentList: [ unnamedArgumentList: [
new SlashCommandArgument( new SlashCommandArgument(
@ -438,7 +458,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'hide',
], ],
helpString: 'Hides a chat message from the prompt.', helpString: 'Hides a chat message from the prompt.',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'unhide', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'unhide',
callback: unhideMessageCallback, callback: unhideMessageCallback,
unnamedArgumentList: [ unnamedArgumentList: [
new SlashCommandArgument( new SlashCommandArgument(
@ -447,7 +468,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'unhide',
], ],
helpString: 'Unhides a message from the prompt.', helpString: 'Unhides a message from the prompt.',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-disable', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'member-disable',
callback: disableGroupMemberCallback, callback: disableGroupMemberCallback,
aliases: ['disable', 'disablemember', 'memberdisable'], aliases: ['disable', 'disablemember', 'memberdisable'],
unnamedArgumentList: [ unnamedArgumentList: [
@ -457,7 +479,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-disab
], ],
helpString: 'Disables a group member from being drafted for replies.', 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'], aliases: ['enable', 'enablemember', 'memberenable'],
callback: enableGroupMemberCallback, callback: enableGroupMemberCallback,
unnamedArgumentList: [ unnamedArgumentList: [
@ -467,7 +490,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-enabl
], ],
helpString: 'Enables a group member to be drafted for replies.', 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, callback: addGroupMemberCallback,
aliases: ['addmember', 'memberadd'], aliases: ['addmember', 'memberadd'],
unnamedArgumentList: [ unnamedArgumentList: [
@ -489,7 +513,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-add',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-remove', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'member-remove',
callback: removeGroupMemberCallback, callback: removeGroupMemberCallback,
aliases: ['removemember', 'memberremove'], aliases: ['removemember', 'memberremove'],
unnamedArgumentList: [ unnamedArgumentList: [
@ -512,7 +537,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-remov
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-up', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'member-up',
callback: moveGroupMemberUpCallback, callback: moveGroupMemberUpCallback,
aliases: ['upmember', 'memberup'], aliases: ['upmember', 'memberup'],
unnamedArgumentList: [ unnamedArgumentList: [
@ -522,7 +548,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-up',
], ],
helpString: 'Moves a group member up in the group chat list.', 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, callback: moveGroupMemberDownCallback,
aliases: ['downmember', 'memberdown'], aliases: ['downmember', 'memberdown'],
unnamedArgumentList: [ unnamedArgumentList: [
@ -532,7 +559,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-down'
], ],
helpString: 'Moves a group member down in the group chat list.', 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, callback: peekCallback,
unnamedArgumentList: [ unnamedArgumentList: [
new SlashCommandArgument( new SlashCommandArgument(
@ -558,7 +586,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'peek',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'delswipe', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'delswipe',
callback: deleteSwipeCallback, callback: deleteSwipeCallback,
aliases: ['swipedel'], aliases: ['swipedel'],
unnamedArgumentList: [ unnamedArgumentList: [
@ -585,7 +614,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'delswipe',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'echo', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'echo',
callback: echoCallback, callback: echoCallback,
returns: 'the text', returns: 'the text',
namedArgumentList: [ namedArgumentList: [
@ -615,7 +645,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'echo',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'gen', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'gen',
callback: generateCallback, callback: generateCallback,
returns: 'generated text', returns: 'generated text',
namedArgumentList: [ namedArgumentList: [
@ -646,7 +677,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'gen',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'genraw', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'genraw',
callback: generateRawCallback, callback: generateRawCallback,
returns: 'generated text', returns: 'generated text',
namedArgumentList: [ namedArgumentList: [
@ -692,7 +724,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'genraw',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'addswipe', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'addswipe',
callback: addSwipeCallback, callback: addSwipeCallback,
aliases: ['swipeadd'], aliases: ['swipeadd'],
unnamedArgumentList: [ unnamedArgumentList: [
@ -702,10 +735,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'addswipe',
], ],
helpString: 'Adds a swipe to the last chat message.', helpString: 'Adds a swipe to the last chat message.',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'abort', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'abort',
callback: abortCallback, callback: abortCallback,
namedArgumentList: [ namedArgumentList: [
SlashCommandNamedArgument.fromProps({ name: 'quiet', SlashCommandNamedArgument.fromProps({
name: 'quiet',
description: 'Whether to suppress the toast message notifying about the /abort call.', description: 'Whether to suppress the toast message notifying about the /abort call.',
typeList: [ARGUMENT_TYPE.BOOLEAN], typeList: [ARGUMENT_TYPE.BOOLEAN],
defaultValue: 'true', defaultValue: 'true',
@ -713,13 +748,15 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'abort',
}), }),
], ],
unnamedArgumentList: [ 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], typeList: [ARGUMENT_TYPE.STRING],
}), }),
], ],
helpString: 'Aborts the slash command batch execution.', helpString: 'Aborts the slash command batch execution.',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'fuzzy', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'fuzzy',
callback: fuzzyCallback, callback: fuzzyCallback,
returns: 'first matching item', returns: 'first matching item',
namedArgumentList: [ namedArgumentList: [
@ -758,7 +795,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'fuzzy',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'pass', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'pass',
callback: (_, arg) => arg, callback: (_, arg) => arg,
returns: 'the provided value', returns: 'the provided value',
unnamedArgumentList: [ unnamedArgumentList: [
@ -779,7 +817,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'pass',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'delay', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'delay',
callback: delayCallback, callback: delayCallback,
aliases: ['wait', 'sleep'], aliases: ['wait', 'sleep'],
unnamedArgumentList: [ unnamedArgumentList: [
@ -801,7 +840,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'delay',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'input', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'input',
aliases: ['prompt'], aliases: ['prompt'],
callback: inputCallback, callback: inputCallback,
returns: 'user input', returns: 'user input',
@ -834,7 +874,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'input',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'run', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'run',
aliases: ['call', 'exec'], aliases: ['call', 'exec'],
callback: runCallback, callback: runCallback,
returns: 'result of the executed closure of QR', returns: 'result of the executed closure of QR',
@ -855,7 +896,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'run',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'messages', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'messages',
callback: getMessagesCallback, callback: getMessagesCallback,
aliases: ['message'], aliases: ['message'],
namedArgumentList: [ namedArgumentList: [
@ -900,7 +942,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'messages',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'setinput', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'setinput',
callback: setInputCallback, callback: setInputCallback,
unnamedArgumentList: [ unnamedArgumentList: [
new SlashCommandArgument( new SlashCommandArgument(
@ -921,7 +964,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'setinput',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'popup', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'popup',
callback: popupCallback, callback: popupCallback,
returns: 'popup text', returns: 'popup text',
namedArgumentList: [ namedArgumentList: [
@ -955,7 +999,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'popup',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'buttons', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'buttons',
callback: buttonsCallback, callback: buttonsCallback,
returns: 'clicked button label', returns: 'clicked button label',
namedArgumentList: [ namedArgumentList: [
@ -983,7 +1028,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'buttons',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trimtokens', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'trimtokens',
callback: trimTokensCallback, callback: trimTokensCallback,
returns: 'trimmed text', returns: 'trimmed text',
namedArgumentList: [ namedArgumentList: [
@ -1013,7 +1059,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trimtokens',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trimstart', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'trimstart',
callback: trimStartCallback, callback: trimStartCallback,
returns: 'trimmed text', returns: 'trimmed text',
unnamedArgumentList: [ unnamedArgumentList: [
@ -1035,7 +1082,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trimstart',
</div> </div>
`, `,
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trimend', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'trimend',
callback: trimEndCallback, callback: trimEndCallback,
returns: 'trimmed text', returns: 'trimmed text',
unnamedArgumentList: [ unnamedArgumentList: [
@ -1045,7 +1093,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'trimend',
], ],
helpString: 'Trims the text to the end of the last full sentence.', 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, callback: injectCallback,
namedArgumentList: [ namedArgumentList: [
new SlashCommandNamedArgument( 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).', 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, callback: listInjectsCallback,
helpString: 'Lists all script injections for the current chat.', helpString: 'Lists all script injections for the current chat.',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'flushinjects', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'flushinjects',
callback: flushInjectsCallback, callback: flushInjectsCallback,
helpString: 'Removes all script injections for the current chat.', 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), callback: (_, text) => getTokenCountAsync(text),
returns: 'number of tokens', returns: 'number of tokens',
unnamedArgumentList: [ unnamedArgumentList: [
@ -1089,7 +1141,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'tokens',
], ],
helpString: 'Counts the number of tokens in the provided text.', helpString: 'Counts the number of tokens in the provided text.',
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'model', SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'model',
callback: modelCallback, callback: modelCallback,
returns: 'current model', returns: 'current model',
unnamedArgumentList: [ unnamedArgumentList: [
@ -2878,6 +2931,20 @@ 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) * @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) { export async function setSlashCommandAutoComplete(textarea, isFloating = false) {
function canUseNegativeLookbehind() {
try {
new RegExp('(?<!_)');
return true;
} catch (e) {
return false;
}
}
if (!canUseNegativeLookbehind()) {
console.warn('Cannot use negative lookbehind in this browser');
return;
}
const parser = new SlashCommandParser(); const parser = new SlashCommandParser();
const ac = new AutoComplete( const ac = new AutoComplete(
textarea, textarea,

View File

@ -109,7 +109,7 @@ export class SlashCommandParser {
return this.text[this.index]; return this.text[this.index];
} }
get endOfText() { 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));
} }

View File

@ -1341,11 +1341,7 @@ export async function extractTextFromHTML(blob, textSelector = 'body') {
*/ */
export async function extractTextFromMarkdown(blob) { export async function extractTextFromMarkdown(blob) {
const markdown = await blob.text(); const markdown = await blob.text();
const converter = new showdown.Converter(); const text = postProcessText(markdown, false);
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);
return text; return text;
} }
@ -1629,15 +1625,31 @@ export function highlightRegex(regexStr) {
regexStr = escapeHtml(regexStr); regexStr = escapeHtml(regexStr);
// Patterns that we want to highlight only if they are not escaped // Patterns that we want to highlight only if they are not escaped
const patterns = { function getPatterns() {
brackets: /(?<!\\)\[.*?\]/g, // Non-escaped squary brackets try {
quantifiers: /(?<!\\)[*+?{}]/g, // Non-escaped quantifiers return {
operators: /(?<!\\)[|.^$()]/g, // Non-escaped operators like | and () brackets: new RegExp('(?<!\\\\)\\[.*?\\]', 'g'), // Non-escaped square brackets
specialChars: /\\./g, quantifiers: new RegExp('(?<!\\\\)[*+?{}]', 'g'), // Non-escaped quantifiers
flags: /(?<=\/)([gimsuy]*)$/g, // Match trailing flags operators: new RegExp('(?<!\\\\)[|.^$()]', 'g'), // Non-escaped operators like | and ()
delimiters: /^\/|(?<![\\<])\//g, // Match leading or trailing delimiters specialChars: new RegExp('\\\\.', 'g'),
flags: new RegExp('(?<=\\/)([gimsuy]*)$', 'g'), // Match trailing flags
delimiters: new RegExp('^\\/|(?<![\\\\<])\\/', 'g'), // Match leading or trailing delimiters
}; };
} catch (error) {
return {
brackets: new RegExp('(\\\\)?\\[.*?\\]', 'g'), // Non-escaped square brackets
quantifiers: new RegExp('(\\\\)?[*+?{}]', 'g'), // Non-escaped quantifiers
operators: new RegExp('(\\\\)?[|.^$()]', 'g'), // Non-escaped operators like | and ()
specialChars: new RegExp('\\\\.', 'g'),
flags: new RegExp('/([gimsuy]*)$', 'g'), // Match trailing flags
delimiters: new RegExp('^/|[^\\\\](/)', 'g'), // Match leading or trailing delimiters
};
}
}
const patterns = getPatterns();
// Function to replace each pattern with a highlighted HTML span // Function to replace each pattern with a highlighted HTML span
const wrapPattern = (pattern, className) => { const wrapPattern = (pattern, className) => {
regexStr = regexStr.replace(pattern, match => `<span class="${className}">${match}</span>`); regexStr = regexStr.replace(pattern, match => `<span class="${className}">${match}</span>`);

View File

@ -186,7 +186,7 @@ class WorldInfoBuffer {
result += '\n' + this.#recurseBuffer.join('\n'); 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 // Otherwise we do normal matching of plaintext with the chosen entry settings
haystack = this.#transformString(haystack, entry);
const transformedString = this.#transformString(needle, entry); const transformedString = this.#transformString(needle, entry);
const matchWholeWords = entry.matchWholeWords ?? world_info_match_whole_words; const matchWholeWords = entry.matchWholeWords ?? world_info_match_whole_words;

View File

@ -693,22 +693,34 @@ body .panelControlBar {
#send_but { #send_but {
visibility: hidden; visibility: hidden;
} }
#rightSendForm>div:not(.mes_send).stscript_btn { #rightSendForm>div:not(.mes_send).stscript_btn {
&.stscript_pause, &.stscript_stop {
&.stscript_pause,
&.stscript_stop {
display: flex; display: flex;
} }
} }
&.script_paused { &.script_paused {
#rightSendForm>div:not(.mes_send).stscript_btn { #rightSendForm>div:not(.mes_send).stscript_btn {
&.stscript_pause { &.stscript_pause {
display: none; display: none;
} }
&.stscript_continue { &.stscript_continue {
display: flex; display: flex;
} }
} }
} }
} }
@supports not selector(&) {
.stscript_btn {
display: none;
}
}
#rightSendForm>div:not(.mes_send) { #rightSendForm>div:not(.mes_send) {
&.stscript_btn { &.stscript_btn {
padding-right: 2px; padding-right: 2px;
@ -717,15 +729,19 @@ body .panelControlBar {
transition: 0.3s; transition: 0.3s;
opacity: 1; opacity: 1;
display: none; display: none;
&.stscript_pause>.fa-solid { &.stscript_pause>.fa-solid {
background-color: rgb(146, 190, 252); background-color: rgb(146, 190, 252);
} }
&.stscript_continue>.fa-solid { &.stscript_continue>.fa-solid {
background-color: rgb(146, 190, 252); background-color: rgb(146, 190, 252);
} }
&.stscript_stop>.fa-solid { &.stscript_stop>.fa-solid {
background-color: rgb(215, 136, 114); background-color: rgb(215, 136, 114);
} }
>.fa-solid { >.fa-solid {
--toastInfoColor: #2F96B4; --toastInfoColor: #2F96B4;
--progColor: rgba(0, 128, 0, 0.839); --progColor: rgba(0, 128, 0, 0.839);
@ -740,8 +756,7 @@ body .panelControlBar {
align-items: center; align-items: center;
box-shadow: box-shadow:
0 0 0 var(--progColor), 0 0 0 var(--progColor),
0 0 0 var(--progColor) 0 0 0 var(--progColor);
;
} }
} }
} }
@ -1140,24 +1155,27 @@ select {
--prog: 0%; --prog: 0%;
--progDone: 0; --progDone: 0;
border-top: var(--progWidth) solid var(--progColor); border-top: var(--progWidth) solid var(--progColor);
clip-path: polygon( clip-path: polygon(0% calc(var(--progDone) * var(--progWidthClip)),
0% calc(var(--progDone) * var(--progWidthClip)),
var(--prog) calc(var(--progDone) * var(--progWidthClip)), var(--prog) calc(var(--progDone) * var(--progWidthClip)),
var(--prog) var(--progWidthClip), var(--prog) var(--progWidthClip),
100% var(--progWidthClip), 100% var(--progWidthClip),
100% 100%, 100% 100%,
0% 100% 0% 100%);
);
transition: clip-path 200ms; transition: clip-path 200ms;
} }
@keyframes script_progress_pulse { @keyframes script_progress_pulse {
0%, 100% {
0%,
100% {
border-top-color: var(--progColor); border-top-color: var(--progColor);
} }
50% { 50% {
border-top-color: var(--progFlashColor); border-top-color: var(--progFlashColor);
} }
} }
#form_sheld.isExecutingCommandsFromChatInput.script_paused #send_textarea { #form_sheld.isExecutingCommandsFromChatInput.script_paused #send_textarea {
animation-name: script_progress_pulse; animation-name: script_progress_pulse;
animation-duration: 1500ms; animation-duration: 1500ms;
@ -1169,9 +1187,11 @@ select {
#form_sheld.script_success #send_textarea { #form_sheld.script_success #send_textarea {
border-top-color: var(--progSuccessColor); border-top-color: var(--progSuccessColor);
} }
#form_sheld.script_error #send_textarea { #form_sheld.script_error #send_textarea {
border-top-color: var(--progErrorColor); border-top-color: var(--progErrorColor);
} }
#form_sheld.script_aborted #send_textarea { #form_sheld.script_aborted #send_textarea {
border-top-color: var(--progAbortedColor); border-top-color: var(--progAbortedColor);
} }
@ -1193,17 +1213,20 @@ select {
--direction: row; --direction: row;
left: 0; left: 0;
right: 0; right: 0;
&:before { &:before {
content: ""; content: "";
flex: 0 1 calc(var(--targetOffset) * 1px); flex: 0 1 calc(var(--targetOffset) * 1px);
display: block; display: block;
pointer-events: none; pointer-events: none;
} }
.autoComplete { .autoComplete {
flex: 0 0 auto; flex: 0 0 auto;
width: 50vw; width: 50vw;
pointer-events: all; pointer-events: all;
} }
&:after { &:after {
content: ""; content: "";
flex: 1 1 0; flex: 1 1 0;
@ -1233,11 +1256,13 @@ select {
flex: 0 1 calc(var(--targetOffset) * 1px - 5vh); flex: 0 1 calc(var(--targetOffset) * 1px - 5vh);
display: block; display: block;
} }
.autoComplete-details { .autoComplete-details {
flex: 0 0 auto; flex: 0 0 auto;
max-height: 80vh; max-height: 80vh;
pointer-events: all; pointer-events: all;
} }
&:after { &:after {
content: ""; content: "";
flex: 1 1 0; flex: 1 1 0;
@ -1248,35 +1273,42 @@ select {
flex-direction: row; flex-direction: row;
left: 0; left: 0;
right: 0; right: 0;
.autoComplete-details { .autoComplete-details {
max-height: unset; max-height: unset;
width: 25vw; width: 25vw;
} }
&.left { &.left {
&:before { &:before {
flex: 0 1 calc(var(--targetOffset) * 1px - 25vw); flex: 0 1 calc(var(--targetOffset) * 1px - 25vw);
} }
&:after { &:after {
flex: 1 0 auto; flex: 1 0 auto;
max-width: 50vw; max-width: 50vw;
} }
} }
&.right { &.right {
&:before { &:before {
flex: 0 0 calc(var(--targetOffset) * 1px + 50vw); flex: 0 0 calc(var(--targetOffset) * 1px + 50vw);
} }
} }
&.full { &.full {
&:before { &:before {
content: ""; content: "";
flex: 0 1 calc(var(--targetOffset) * 1px); flex: 0 1 calc(var(--targetOffset) * 1px);
display: block; display: block;
} }
.autoComplete-details { .autoComplete-details {
flex: 0 0 auto; flex: 0 0 auto;
max-width: 50vw; max-width: 50vw;
width: unset; width: unset;
} }
&:after { &:after {
content: ""; content: "";
flex: 1 1 0; 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-currentParenthesis: rgba(195 118 210 / 1);
--ac-style-color-comment: rgba(122 151 90 / 1); --ac-style-color-comment: rgba(122 151 90 / 1);
} }
body[data-stscript-style="light"] { body[data-stscript-style="light"] {
--ac-style-color-border: rgba(200 200 200 / 1); --ac-style-color-border: rgba(200 200 200 / 1);
--ac-style-color-background: rgba(248 248 248 / 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-currentParenthesis: rgba(195 118 210 / 1);
--ac-style-color-comment: rgba(70 126 26 / 1); --ac-style-color-comment: rgba(70 126 26 / 1);
} }
body[data-stscript-style="theme"] { body[data-stscript-style="theme"] {
--ac-style-color-border: var(--SmartThemeBorderColor); --ac-style-color-border: var(--SmartThemeBorderColor);
--ac-style-color-background: var(--SmartThemeBlurTintColor); --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-currentParenthesis: rgba(195 118 210 / 1);
--ac-style-color-comment: rgba(122 151 90 / 1); --ac-style-color-comment: rgba(122 151 90 / 1);
} }
body { body {
--ac-font-scale: 0.8; --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-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-background: var(--ac-style-color-background, rgba(32 32 32 / 1));
--ac-color-text: var(--ac-style-color-text, rgba(204 204 204 / 1)); --ac-color-text: var(--ac-style-color-text, rgba(204 204 204 / 1));
@ -1394,47 +1431,121 @@ body {
line-height: 1.2; line-height: 1.2;
text-align: left; text-align: left;
z-index: 10000; z-index: 10000;
* { text-shadow: none; }
* {
text-shadow: none;
} }
}
body[data-stscript-style] .autoComplete [data-option-type] { body[data-stscript-style] .autoComplete [data-option-type] {
&[data-option-type="enum"] .type { color: var(--ac-color-string); } &[data-option-type="enum"] .type {
&[data-option-type="command"] .type { color: var(--ac-color-cmd); } color: var(--ac-color-string);
&[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="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 { body[data-stscript-style] .hljs.language-stscript {
* { text-shadow: none !important; } * {
text-shadow: none !important;
}
text-shadow: none !important; text-shadow: none !important;
background-color: var(--ac-style-color-background); background-color: var(--ac-style-color-background);
color: var(--ac-style-color-text); color: var(--ac-style-color-text);
.hljs-title.function_ { color: var(--ac-style-color-cmd); } .hljs-title.function_ {
.hljs-title.function_.invoke__ { color: var(--ac-style-color-cmd); } 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-title.function_.invoke__ {
.hljs-variable.language_ { color: var(--ac-style-color-variableLanguage); } color: var(--ac-style-color-cmd);
.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-string {
.hljs-comment { color: var(--ac-style-color-comment); } color: var(--ac-style-color-string);
.hljs-abort { color: var(--ac-style-color-abort, #e38e23); } }
.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-closure {
> .hljs-punctuation { color: var(--ac-style-color-punctuation); } >.hljs-punctuation {
color: var(--ac-style-color-punctuation);
}
.hljs-closure { .hljs-closure {
> .hljs-punctuation { color: var(--ac-style-color-punctuationL1); } >.hljs-punctuation {
color: var(--ac-style-color-punctuationL1);
}
.hljs-closure { .hljs-closure {
> .hljs-punctuation { color: var(--ac-style-color-punctuationL2); } >.hljs-punctuation {
color: var(--ac-style-color-punctuationL2);
}
.hljs-closure { .hljs-closure {
> .hljs-punctuation { color: var(--ac-style-color-punctuation); } >.hljs-punctuation {
color: var(--ac-style-color-punctuation);
}
.hljs-closure { .hljs-closure {
> .hljs-punctuation { color: var(--ac-style-color-punctuationL1); } >.hljs-punctuation {
color: var(--ac-style-color-punctuationL1);
}
.hljs-closure { .hljs-closure {
> .hljs-punctuation { color: var(--ac-style-color-punctuationL2); } >.hljs-punctuation {
color: var(--ac-style-color-punctuationL2);
}
} }
} }
} }
@ -1450,6 +1561,7 @@ body[data-stscript-style] .hljs.language-stscript {
align-items: center; align-items: center;
max-height: calc(95vh - var(--bottom)); max-height: calc(95vh - var(--bottom));
container-type: inline-size; container-type: inline-size;
>.item { >.item {
cursor: pointer; cursor: pointer;
padding: 3px; padding: 3px;
@ -1457,10 +1569,12 @@ body[data-stscript-style] .hljs.language-stscript {
display: flex; display: flex;
gap: 0.5em; gap: 0.5em;
display: contents; display: contents;
@container (max-width: 80em) { @container (max-width: 80em) {
.specs { .specs {
grid-column: 2 / 4; grid-column: 2 / 4;
} }
>.help { >.help {
grid-column: 2 / 4; grid-column: 2 / 4;
padding-left: 1em; padding-left: 1em;
@ -1468,21 +1582,26 @@ body[data-stscript-style] .hljs.language-stscript {
height: auto; height: auto;
} }
} }
&.blank { &.blank {
display: block; display: block;
grid-column: 1 / 4; grid-column: 1 / 4;
} }
&:hover>* { &:hover>* {
background-color: var(--ac-color-hoveredBackground); background-color: var(--ac-color-hoveredBackground);
color: var(--ac-color-hoveredText); color: var(--ac-color-hoveredText);
} }
&.selected>* { &.selected>* {
background-color: var(--ac-color-selectedBackground); background-color: var(--ac-color-selectedBackground);
color: var(--ac-color-selectedText); color: var(--ac-color-selectedText);
} }
>* { >* {
height: 100%; height: 100%;
} }
>*+* { >*+* {
padding-left: 0.5em; padding-left: 0.5em;
} }
@ -1501,8 +1620,10 @@ body[data-stscript-style] .hljs.language-stscript {
/* &:before { content: "["; } /* &:before { content: "["; }
&:after { content: "]"; } */ &:after { content: "]"; } */
} }
>.specs { >.specs {
align-items: flex-start; align-items: flex-start;
>.name { >.name {
>.matched { >.matched {
background-color: var(--ac-color-matchedBackground); background-color: var(--ac-color-matchedBackground);
@ -1510,24 +1631,30 @@ body[data-stscript-style] .hljs.language-stscript {
font-weight: bold; font-weight: bold;
} }
} }
>.body { >.body {
flex-wrap: wrap; flex-wrap: wrap;
column-gap: 0.5em; column-gap: 0.5em;
>.arguments { >.arguments {
display: contents; display: contents;
height: 100%; height: 100%;
} }
} }
} }
>.help { >.help {
height: 100%; height: 100%;
>.helpContent { >.helpContent {
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
font-size: 0.9em;white-space: nowrap; font-size: 0.9em;
white-space: nowrap;
line-height: 1.2; line-height: 1.2;
max-height: 1.2em; max-height: 1.2em;
display: block; display: block;
>* { >* {
display: contents; display: contents;
} }
@ -1535,29 +1662,36 @@ body[data-stscript-style] .hljs.language-stscript {
} }
} }
} }
.autoComplete-details { .autoComplete-details {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.5em; gap: 0.5em;
>.specs { >.specs {
cursor: default; cursor: default;
flex-direction: column; flex-direction: column;
padding: 0.25em 0.25em 0.5em 0.25em; padding: 0.25em 0.25em 0.5em 0.25em;
border-bottom: 1px solid var(--ac-color-border); border-bottom: 1px solid var(--ac-color-border);
>.name { >.name {
font-weight: bold; font-weight: bold;
color: var(--ac-color-text); color: var(--ac-color-text);
cursor: help; cursor: help;
&:hover { &:hover {
text-decoration: 1px dotted underline; text-decoration: 1px dotted underline;
} }
} }
>.body { >.body {
flex-direction: column; flex-direction: column;
gap: 0.5em; gap: 0.5em;
>.arguments { >.arguments {
margin: 0; margin: 0;
padding-left: 1.25em; padding-left: 1.25em;
>.argumentItem::marker { >.argumentItem::marker {
color: color-mix(in srgb, var(--ac-color-text), var(--ac-style-color-background)); color: color-mix(in srgb, var(--ac-color-text), var(--ac-style-color-background));
} }
@ -1565,166 +1699,212 @@ body[data-stscript-style] .hljs.language-stscript {
.argumentSpec { .argumentSpec {
display: flex; display: flex;
gap: 0.5em; gap: 0.5em;
.argument-default { .argument-default {
&:before { &:before {
content: " = "; content: " = ";
color: var(--ac-color-text); color: var(--ac-color-text);
} }
color: var(--ac-color-string); color: var(--ac-color-string);
} }
} }
.argument { .argument {
cursor: help; cursor: help;
&:hover:not(:has(.argument-name:hover, .argument-types:hover, .argument-enums:hover)) { &:hover:not(:has(.argument-name:hover, .argument-types:hover, .argument-enums:hover)) {
text-decoration: 1px dotted underline; text-decoration: 1px dotted underline;
} }
} }
.argument-name, .argument-name,
.argument-types, .argument-types,
.argument-enums, .argument-enums,
.argument-default .argument-default {
{
cursor: help; cursor: help;
&:hover { &:hover {
text-decoration: 1px dotted underline; text-decoration: 1px dotted underline;
} }
} }
.argument.optional+.argument-description:before, .argument.optional+.argument-description:before,
.argumentSpec:has(.argument.optional) + .argument-description:before .argumentSpec:has(.argument.optional)+.argument-description:before {
{
content: "(optional) "; content: "(optional) ";
color: var(--ac-color-text); color: var(--ac-color-text);
opacity: 0.5; opacity: 0.5;
} }
.argument-description { .argument-description {
margin-left: 0.5em; margin-left: 0.5em;
font-family: var(--mainFontFamily); font-family: var(--mainFontFamily);
font-size: 0.9em; font-size: 0.9em;
} }
} }
.returns { .returns {
cursor: help; cursor: help;
&:hover { &:hover {
text-decoration: 1px dotted underline; text-decoration: 1px dotted underline;
} }
} }
} }
} }
>.help { >.help {
padding: 0 0.5em 0.5em 0.5em; padding: 0 0.5em 0.5em 0.5em;
div { div {
margin-block-end: 1em; margin-block-end: 1em;
} }
ul { ul {
margin: 0; margin: 0;
padding-left: 1.5em; padding-left: 1.5em;
} }
pre { pre {
margin: 0; margin: 0;
>code { >code {
display: block; display: block;
padding: 0; padding: 0;
} }
} }
} }
>.aliases { >.aliases {
padding: 0 0.5em 0.5em 0.5em; padding: 0 0.5em 0.5em 0.5em;
&:before { content: '(alias: '; }
&:before {
content: '(alias: ';
}
>.alias { >.alias {
font-family: monospace; font-family: monospace;
&+.alias:before { content: ', '; }
} &+.alias:before {
&:after { content: ')'; } content: ', ';
} }
} }
.autoComplete > .item, .autoComplete-details { &:after {
content: ')';
}
}
}
.autoComplete>.item,
.autoComplete-details {
>.specs { >.specs {
display: flex; display: flex;
gap: 0.5em; gap: 0.5em;
>.name { >.name {
font-family: monospace; font-family: monospace;
white-space: nowrap; white-space: nowrap;
/* color: var(--ac-color-text); */ /* color: var(--ac-color-text); */
} }
>.body { >.body {
display: flex; display: flex;
>.arguments { >.arguments {
font-family: monospace; font-family: monospace;
.argument { .argument {
white-space: nowrap; white-space: nowrap;
&.namedArgument { &.namedArgument {
&:before { &:before {
content: "["; content: "[";
color: var(--ac-color-text); color: var(--ac-color-text);
} }
&:after { &:after {
content: "]"; content: "]";
color: var(--ac-color-text); color: var(--ac-color-text);
} }
&.optional:after { &.optional:after {
content: "]?"; content: "]?";
color: var(--ac-color-text); color: var(--ac-color-text);
} }
>.argument-name { >.argument-name {
color: var(--ac-color-argName); color: var(--ac-color-argName);
} }
} }
&.unnamedArgument { &.unnamedArgument {
&:before { &:before {
content: "("; content: "(";
color: var(--ac-color-text); color: var(--ac-color-text);
} }
&.multiple:before { &.multiple:before {
content: "...("; content: "...(";
color: var(--ac-color-text); color: var(--ac-color-text);
} }
&:after { &:after {
content: ")"; content: ")";
color: var(--ac-color-text); color: var(--ac-color-text);
} }
&.optional:after { &.optional:after {
content: ")?"; content: ")?";
color: var(--ac-color-text); color: var(--ac-color-text);
} }
} }
>.argument-name+.argument-types:before { >.argument-name+.argument-types:before {
content: "="; content: "=";
color: var(--ac-color-text); color: var(--ac-color-text);
} }
>.argument-types { >.argument-types {
color: var(--ac-color-type); color: var(--ac-color-type);
word-break: break-all; word-break: break-all;
white-space: break-spaces; white-space: break-spaces;
>.argument-type+.argument-type:before { >.argument-type+.argument-type:before {
content: "|"; content: "|";
color: var(--ac-color-text); color: var(--ac-color-text);
};
} }
;
}
>.argument-types+.argument-enums, >.argument-types+.argument-enums,
> .argument-name + .argument-enums >.argument-name+.argument-enums {
{
&:before { &:before {
content: "="; content: "=";
color: var(--ac-color-text); color: var(--ac-color-text);
} }
} }
>.argument-enums { >.argument-enums {
color: var(--ac-color-string); color: var(--ac-color-string);
word-break: break-all; word-break: break-all;
white-space: break-spaces; white-space: break-spaces;
>.argument-enum+.argument-enum:before { >.argument-enum+.argument-enum:before {
content: "|"; content: "|";
color: var(--ac-color-text); color: var(--ac-color-text);
}; }
;
} }
} }
} }
>.returns { >.returns {
font-family: monospace; font-family: monospace;
color: var(--ac-color-text); color: var(--ac-color-text);
&:before { &:before {
content: "=> "; content: "=> ";
color: var(--ac-color-symbol); color: var(--ac-color-symbol);
@ -1733,55 +1913,67 @@ body[data-stscript-style] .hljs.language-stscript {
} }
} }
} }
@media screen and (max-width: 1000px) { @media screen and (max-width: 1000px) {
.autoComplete-wrap { .autoComplete-wrap {
left: 1vw; left: 1vw;
right: 1vw; right: 1vw;
} }
.autoComplete-detailsWrap:not(.full) { .autoComplete-detailsWrap:not(.full) {
left: 50vw; left: 50vw;
} }
} }
.slashCommandBrowser { .slashCommandBrowser {
>.search { >.search {
display: flex; display: flex;
gap: 1em; gap: 1em;
align-items: baseline; align-items: baseline;
white-space: nowrap; white-space: nowrap;
>.searchLabel { >.searchLabel {
flex: 1 1 auto; flex: 1 1 auto;
display: flex; display: flex;
gap: 0.5em; gap: 0.5em;
align-items: baseline; align-items: baseline;
>.searchInput { >.searchInput {
flex: 1 1 auto; flex: 1 1 auto;
} }
} }
>.searchOptions { >.searchOptions {
display: flex; display: flex;
gap: 1em; gap: 1em;
align-items: baseline; align-items: baseline;
} }
} }
>.commandContainer { >.commandContainer {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
container-type: inline-size; container-type: inline-size;
>.autoComplete { >.autoComplete {
flex: 1 1 auto; flex: 1 1 auto;
max-height: unset; max-height: unset;
>.isFiltered { >.isFiltered {
display: none; display: none;
} }
.specs { .specs {
grid-column: 2 / 4; grid-column: 2 / 4;
} }
.help { .help {
grid-column: 2 / 4; grid-column: 2 / 4;
padding-left: 1em; padding-left: 1em;
opacity: 0.75; opacity: 0.75;
} }
} }
>.autoComplete-detailsWrap { >.autoComplete-detailsWrap {
flex: 0 0 auto; flex: 0 0 auto;
align-self: stretch; align-self: stretch;
@ -1791,10 +1983,12 @@ body[data-stscript-style] .hljs.language-stscript {
&:before { &:before {
flex: 0 1 calc(var(--targetOffset) * 1px); flex: 0 1 calc(var(--targetOffset) * 1px);
} }
>.autoComplete-details { >.autoComplete-details {
max-height: 50vh; max-height: 50vh;
} }
} }
@container (max-width: 1000px) { @container (max-width: 1000px) {
>.autoComplete-detailsWrap { >.autoComplete-detailsWrap {
width: 50%; width: 50%;
@ -3371,15 +3565,18 @@ input[type="range"]::-webkit-slider-thumb {
--markerWidth: 15px; --markerWidth: 15px;
container-type: inline-size; container-type: inline-size;
container-name: doubleRangeContainer; container-name: doubleRangeContainer;
>.doubleRangeInputContainer { >.doubleRangeInputContainer {
flex: 0 0 50%; flex: 0 0 50%;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
>datalist { >datalist {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
font-size: x-small; font-size: x-small;
>option { >option {
flex: 0 0 0; flex: 0 0 0;
width: 0; width: 0;
@ -3387,22 +3584,27 @@ input[type="range"]::-webkit-slider-thumb {
justify-content: center; justify-content: center;
} }
} }
@container doubleRangeContainer (max-width: 200px) { @container doubleRangeContainer (max-width: 200px) {
>datalist { >datalist {
height: 2.5em; height: 2.5em;
} }
&:nth-child(1)>datalist>option { &:nth-child(1)>datalist>option {
transform: rotate(-45deg); transform: rotate(-45deg);
transform-origin: bottom right; transform-origin: bottom right;
} }
&:nth-child(2)>datalist>option { &:nth-child(2)>datalist>option {
transform: rotate(45deg); transform: rotate(45deg);
transform-origin: bottom left; transform-origin: bottom left;
} }
} }
>input::-webkit-slider-thumb { >input::-webkit-slider-thumb {
z-index: 2; z-index: 2;
} }
&:after { &:after {
/* shifted to center to hide corners of the inset shadow */ /* shifted to center to hide corners of the inset shadow */
--shift: 2px; --shift: 2px;
@ -3422,34 +3624,42 @@ input[type="range"]::-webkit-slider-thumb {
background-color: var(--SmartThemeQuoteColor); background-color: var(--SmartThemeQuoteColor);
box-shadow: inset 0 0 2px black; box-shadow: inset 0 0 2px black;
} }
&:nth-child(1) { &:nth-child(1) {
--value: 0; --value: 0;
padding-left: 1em; padding-left: 1em;
>input { >input {
direction: rtl; direction: rtl;
position: relative; position: relative;
padding-right: max(20px, 20%); padding-right: max(20px, 20%);
} }
>datalist { >datalist {
direction: rtl; direction: rtl;
padding-right: calc(var(--markerWidth)/2 + max(20px, 20%)); padding-right: calc(var(--markerWidth)/2 + max(20px, 20%));
padding-left: calc(var(--markerWidth)/2 - 2px); padding-left: calc(var(--markerWidth)/2 - 2px);
} }
&:after { &:after {
right: -2px; right: -2px;
} }
} }
&:nth-child(2) { &:nth-child(2) {
--value: 0; --value: 0;
padding-right: 1em; padding-right: 1em;
>input { >input {
position: relative; position: relative;
padding-left: max(20px, 20%); padding-left: max(20px, 20%);
} }
>datalist { >datalist {
padding-left: calc(var(--markerWidth)/2 + max(20px, 20%)); padding-left: calc(var(--markerWidth)/2 + max(20px, 20%));
padding-right: calc(var(--markerWidth)/2 - 2px); padding-right: calc(var(--markerWidth)/2 - 2px);
} }
&:after { &:after {
left: -2px; left: -2px;
} }
@ -4278,6 +4488,7 @@ a {
#CustomCSS-textAreaBlock { #CustomCSS-textAreaBlock {
display: contents; display: contents;
} }
#customCSS { #customCSS {
flex: 1 1 auto; flex: 1 1 auto;
} }
@ -4666,6 +4877,7 @@ body:not(.movingUI) .drawer-content.maximized {
backdrop-filter: blur(var(--SmartThemeBlurStrength)); backdrop-filter: blur(var(--SmartThemeBlurStrength));
background-color: var(--SmartThemeBlurTintColor); background-color: var(--SmartThemeBlurTintColor);
padding: 5px; padding: 5px;
border: 1px solid red;
} }
.zoomed_avatar { .zoomed_avatar {
@ -4683,12 +4895,13 @@ body:not(.movingUI) .drawer-content.maximized {
position: absolute; position: absolute;
height: auto; height: auto;
max-height: 90vh !important; 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; display: none;
} } */
.zoomed_avatar_container { .zoomed_avatar_container {
width: 100%; width: 100%;
@ -4887,10 +5100,39 @@ body:not(.movingUI) .drawer-content.maximized {
} }
/* CSS styles using a consistent pastel color palette */ /* CSS styles using a consistent pastel color palette */
.regex-brackets { color: #FFB347; } /* Pastel Orange */ .regex-brackets {
.regex-special { color: #B0E0E6; } /* Powder Blue */ color: #FFB347;
.regex-quantifier { color: #DDA0DD; } /* Plum */ }
.regex-operator { color: #FFB6C1; } /* Light Pink */
.regex-flags { color: #98FB98; } /* Pale Green */ /* Pastel Orange */
.regex-delimiter { font-weight: bold; color: #FF6961; } /* Pastel Red */ .regex-special {
.regex-highlight { color: #FAF8F6; } /* Pastel White */ 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 */

View File

@ -509,6 +509,40 @@ async function downloadGenericPng(url) {
return null; 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 * @param {String} url
* @returns {String | null } UUID of the character * @returns {String | null } UUID of the character
@ -563,6 +597,7 @@ router.post('/importURL', jsonParser, async (request, response) => {
const isJannnyContent = host.includes('janitorai'); const isJannnyContent = host.includes('janitorai');
const isPygmalionContent = host.includes('pygmalion.chat'); const isPygmalionContent = host.includes('pygmalion.chat');
const isAICharacterCardsContent = host.includes('aicharactercards.com'); const isAICharacterCardsContent = host.includes('aicharactercards.com');
const isRisu = host.includes('realm.risuai.net');
const isGeneric = isHostWhitelisted(host); const isGeneric = isHostWhitelisted(host);
if (isPygmalionContent) { if (isPygmalionContent) {
@ -603,6 +638,14 @@ router.post('/importURL', jsonParser, async (request, response) => {
else { else {
return response.sendStatus(404); 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) { } else if (isGeneric) {
console.log('Downloading from generic url.'); console.log('Downloading from generic url.');
type = 'character'; type = 'character';