mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Extract system message templates to template files
This commit is contained in:
@ -63,42 +63,8 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="css/bg_load.css">
|
<link rel="stylesheet" href="css/bg_load.css">
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
<script>
|
<script type="module" src="scripts/i18n.js"></script>
|
||||||
function applyLocale() {
|
<script type="module" src="script.js"></script>
|
||||||
const overrideLanguage = localStorage.getItem("language");
|
|
||||||
var language = overrideLanguage || navigator.language || navigator.userLanguage;
|
|
||||||
language = language.toLowerCase();
|
|
||||||
console.log(language)
|
|
||||||
//load the appropriate language file
|
|
||||||
$.getJSON("i18n.json", function (data) {
|
|
||||||
console.log(data)
|
|
||||||
if (data.lang.indexOf(language) < 0) language = "en";
|
|
||||||
console.log(language)
|
|
||||||
//find all the elements with `data-i18n` attribute
|
|
||||||
$("[data-i18n]").each(function () {
|
|
||||||
//read the translation from the language data
|
|
||||||
const keys = $(this).data("i18n").split(';'); // Multi-key entries are ; delimited
|
|
||||||
for (const key of keys) {
|
|
||||||
const attrmatch = key.match(/\[(\S+)\](.+)/); // [attribute]key
|
|
||||||
if (attrmatch) { // attribute-tagged key
|
|
||||||
const locval = data?.[language]?.[attrmatch[2]];
|
|
||||||
if (locval) {
|
|
||||||
$(this).attr(attrmatch[1], locval);
|
|
||||||
}
|
|
||||||
} else { // No attribute tag, treat as 'text'
|
|
||||||
const locval = data?.[language]?.[key];
|
|
||||||
if (locval) {
|
|
||||||
$(this).text(locval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$(document).ready(applyLocale);
|
|
||||||
window["applyLocale"] = applyLocale;
|
|
||||||
</script>
|
|
||||||
<script type=module src="script.js"></script>
|
|
||||||
|
|
||||||
<script type="module" src="scripts/world-info.js"></script>
|
<script type="module" src="scripts/world-info.js"></script>
|
||||||
<script type="module" src="scripts/group-chats.js"></script>
|
<script type="module" src="scripts/group-chats.js"></script>
|
||||||
|
325
public/script.js
325
public/script.js
@ -170,6 +170,7 @@ import {
|
|||||||
getInstructStoppingSequences,
|
getInstructStoppingSequences,
|
||||||
autoSelectInstructPreset,
|
autoSelectInstructPreset,
|
||||||
} from "./scripts/instruct-mode.js";
|
} from "./scripts/instruct-mode.js";
|
||||||
|
import { applyLocale } from "./scripts/i18n.js";
|
||||||
|
|
||||||
//exporting functions and vars for mods
|
//exporting functions and vars for mods
|
||||||
export {
|
export {
|
||||||
@ -241,6 +242,14 @@ export {
|
|||||||
printCharacters,
|
printCharacters,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow target="_blank" in links
|
||||||
|
DOMPurify.addHook('afterSanitizeAttributes', function (node) {
|
||||||
|
if ('target' in node) {
|
||||||
|
node.setAttribute('target', '_blank');
|
||||||
|
node.setAttribute('rel', 'noopener');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// API OBJECT FOR EXTERNAL WIRING
|
// API OBJECT FOR EXTERNAL WIRING
|
||||||
window["SillyTavern"] = {};
|
window["SillyTavern"] = {};
|
||||||
|
|
||||||
@ -357,186 +366,102 @@ const extension_prompt_types = {
|
|||||||
IN_CHAT: 1
|
IN_CHAT: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
const system_messages = {
|
let system_messages = {};
|
||||||
help: {
|
|
||||||
name: systemUserName,
|
|
||||||
force_avatar: system_avatar,
|
|
||||||
is_user: false,
|
|
||||||
is_system: true,
|
|
||||||
is_name: true,
|
|
||||||
mes:
|
|
||||||
`Hello there! Please select the help topic you would like to learn more about:
|
|
||||||
<ul>
|
|
||||||
<li><a href="#" data-displayHelp="1">Slash Commands</a> (or <tt>/help slash</tt>)</li>
|
|
||||||
<li><a href="#" data-displayHelp="2">Formatting</a> (or <tt>/help format</tt>)</li>
|
|
||||||
<li><a href="#" data-displayHelp="3">Hotkeys</a> (or <tt>/help hotkeys</tt>)</li>
|
|
||||||
<li><a href="#" data-displayHelp="4">{{Macros}}</a> (or <tt>/help macros</tt>)</li>
|
|
||||||
</ul>
|
|
||||||
<br><b>Still got questions left? The <a target="_blank" href="https://docs.sillytavern.app/">Official SillyTavern Documentation Website</a> has much more information!</b>`
|
|
||||||
},
|
|
||||||
slash_commands: {
|
|
||||||
name: systemUserName,
|
|
||||||
force_avatar: system_avatar,
|
|
||||||
is_user: false,
|
|
||||||
is_system: true,
|
|
||||||
is_name: true,
|
|
||||||
mes: '',
|
|
||||||
},
|
|
||||||
hotkeys: {
|
|
||||||
name: systemUserName,
|
|
||||||
force_avatar: system_avatar,
|
|
||||||
is_user: false,
|
|
||||||
is_system: true,
|
|
||||||
is_name: true,
|
|
||||||
mes:
|
|
||||||
`Hotkeys/Keybinds:
|
|
||||||
<ul>
|
|
||||||
<li><tt>Up</tt> = Edit last message in chat</li>
|
|
||||||
<li><tt>Ctrl+Up</tt> = Edit last USER message in chat</li>
|
|
||||||
<li><tt>Left</tt> = swipe left</li>
|
|
||||||
<li><tt>Right</tt> = swipe right (NOTE: swipe hotkeys are disabled when chatbar has something typed into it)</li>
|
|
||||||
<li><tt>Ctrl+Left</tt> = view locally stored variables (in the browser console window)</li>
|
|
||||||
<li><tt>Enter</tt> (with chat bar selected) = send your message to AI</li>
|
|
||||||
<li><tt>Ctrl+Enter</tt> = Regenerate the last AI response</li>
|
|
||||||
<li><tt>Escape</tt> = stop AI response generation</li>
|
|
||||||
<li><tt>Ctrl+Shift+Up</tt> = Scroll to context line</li>
|
|
||||||
<li><tt>Ctrl+Shift+Down</tt> = Scroll chat to bottom</li>
|
|
||||||
</ul>`
|
|
||||||
},
|
|
||||||
formatting: {
|
|
||||||
name: systemUserName,
|
|
||||||
force_avatar: system_avatar,
|
|
||||||
is_user: false,
|
|
||||||
is_system: true,
|
|
||||||
is_name: true,
|
|
||||||
mes:
|
|
||||||
`Text formatting commands:
|
|
||||||
<ul>
|
|
||||||
<li><tt>*text*</tt> - displays as <i>italics</i></li>
|
|
||||||
<li><tt>**text**</tt> - displays as <b>bold</b></li>
|
|
||||||
<li><tt>***text***</tt> - displays as <b><i>bold italics</i></b></li>
|
|
||||||
<li><tt>` + "```" + `text` + "```" + `</tt> - displays as a code block (new lines allowed between the backticks)</li>
|
|
||||||
<pre>
|
|
||||||
<code>
|
|
||||||
like
|
|
||||||
this
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
<li><tt>` + "`" + `text` + "`" + `</tt> - displays as <code>inline code</code></li>
|
|
||||||
<li><tt>` + "> " + `text` + `</tt> - displays as a blockquote (note the space after >)</li>
|
|
||||||
<blockquote>like this</blockquote>
|
|
||||||
<li><tt>` + "# " + `text` + `</tt> - displays as a large header (note the space)</li>
|
|
||||||
<h1>like this</h1>
|
|
||||||
<li><tt>` + "## " + `text` + `</tt> - displays as a medium header (note the space)</li>
|
|
||||||
<h2>like this</h2>
|
|
||||||
<li><tt>` + "### " + `text` + `</tt> - displays as a small header (note the space)</li>
|
|
||||||
<h3>like this</h3>
|
|
||||||
<li><tt>$$ text $$</tt> - renders a LaTeX formula (if enabled)</li>
|
|
||||||
<li><tt>$ text $</tt> - renders an AsciiMath formula (if enabled)</li>
|
|
||||||
</ul>`
|
|
||||||
},
|
|
||||||
macros: {
|
|
||||||
name: systemUserName,
|
|
||||||
force_avatar: system_avatar,
|
|
||||||
is_user: false,
|
|
||||||
is_system: true,
|
|
||||||
is_name: true,
|
|
||||||
mes:
|
|
||||||
`System-wide Replacement Macros:
|
|
||||||
<ul>
|
|
||||||
<li><tt>{{user}}</tt> - your current Persona username</li>
|
|
||||||
<li><tt>{{char}}</tt> - the Character's name</li>
|
|
||||||
<li><tt>{{input}}</tt> - the user input</li>
|
|
||||||
<li><tt>{{time}}</tt> - the current time</li>
|
|
||||||
<li><tt>{{date}}</tt> - the current date</li>
|
|
||||||
<li><tt>{{idle_duration}}</tt> - the time since the last user message was sent</li>
|
|
||||||
<li><tt>{{random:(args)}}</tt> - returns a random item from the list. (ex: {{random:1,2,3,4}} will return 1 of the 4 numbers at random. Works with text lists too.</li>
|
|
||||||
<li><tt>{{roll:(formula)}}</tt> - rolls a dice. (ex: {{roll:1d6}} will roll a 6-sided dice and return a number between 1 and 6)</li>
|
|
||||||
</ul>`
|
|
||||||
},
|
|
||||||
welcome:
|
|
||||||
{
|
|
||||||
name: systemUserName,
|
|
||||||
force_avatar: system_avatar,
|
|
||||||
is_user: false,
|
|
||||||
is_system: true,
|
|
||||||
is_name: true,
|
|
||||||
mes: [
|
|
||||||
'<h3><span id="version_display_welcome">SillyTavern</span><div id="version_display_welcome"></div></h3>',
|
|
||||||
"<a href='https://docs.sillytavern.app/usage/update/' target='_blank'>Want to update?</a>",
|
|
||||||
'<hr>',
|
|
||||||
'<h3>How to start chatting?</h3>',
|
|
||||||
'<ol>',
|
|
||||||
'<li>Click <code><i class="fa-solid fa-plug"></i></code> and select a <a href="https://docs.sillytavern.app/usage/api-connections/" target_"blank">Chat API</a>.</li>',
|
|
||||||
'<li>Click <code><i class="fa-solid fa-address-card"></i></code> and pick a character</li>',
|
|
||||||
'</ol>',
|
|
||||||
'<hr>',
|
|
||||||
'<h3>Want more characters?</h3>',
|
|
||||||
'<i>Not controlled by SillyTavern team.</i>',
|
|
||||||
'<ul>',
|
|
||||||
'<li><a target="_blank" href="https://discord.gg/pygmalionai">Pygmalion AI Discord</a></li>',
|
|
||||||
'<li><a target="_blank" href="https://chub.ai/">Chub (NSFW)</a></li>',
|
|
||||||
'</ul>',
|
|
||||||
'<hr>',
|
|
||||||
'<h3>Confused or lost?</h3>',
|
|
||||||
'<ul>',
|
|
||||||
'<li><span class="note-link-span">?</span> - click these icons!</li>',
|
|
||||||
'<li>Enter <code>/?</code> in the chat bar</li>',
|
|
||||||
'<li><a target="_blank" href="https://docs.sillytavern.app/">SillyTavern Documentation Site</a></li>',
|
|
||||||
'<li><a target="_blank" href="https://docs.sillytavern.app/extras/installation/">Extras Installation Guide</a></li>',
|
|
||||||
|
|
||||||
'</ul>',
|
function getSystemMessages() {
|
||||||
|
system_messages = {
|
||||||
'<hr>',
|
help: {
|
||||||
'<h3>Still have questions?</h3 > ',
|
name: systemUserName,
|
||||||
'<ul>',
|
force_avatar: system_avatar,
|
||||||
'<li><a target="_blank" href="https://discord.gg/RZdyAEUPvj">Join the SillyTavern Discord</a></li>',
|
is_user: false,
|
||||||
'<li><a target="_blank" href="https://github.com/SillyTavern/SillyTavern/issues">Post a GitHub issue</a></li>',
|
is_system: true,
|
||||||
'<li><a target="_blank" href="https://github.com/SillyTavern/SillyTavern#questions-or-suggestions">Contact the developers</a></li>',
|
is_name: true,
|
||||||
].join('')
|
mes: renderTemplate("help"),
|
||||||
},
|
},
|
||||||
group: {
|
slash_commands: {
|
||||||
name: systemUserName,
|
name: systemUserName,
|
||||||
force_avatar: system_avatar,
|
force_avatar: system_avatar,
|
||||||
is_user: false,
|
is_user: false,
|
||||||
is_system: true,
|
is_system: true,
|
||||||
is_name: true,
|
is_name: true,
|
||||||
is_group: true,
|
mes: '',
|
||||||
mes: "Group chat created. Say 'Hi' to lovely people!",
|
},
|
||||||
},
|
hotkeys: {
|
||||||
empty: {
|
name: systemUserName,
|
||||||
name: systemUserName,
|
force_avatar: system_avatar,
|
||||||
force_avatar: system_avatar,
|
is_user: false,
|
||||||
is_user: false,
|
is_system: true,
|
||||||
is_system: true,
|
is_name: true,
|
||||||
is_name: true,
|
mes: renderTemplate("hotkeys"),
|
||||||
mes: "No one hears you. <b>Hint:</b> add more members to the group!",
|
},
|
||||||
},
|
formatting: {
|
||||||
generic: {
|
name: systemUserName,
|
||||||
name: systemUserName,
|
force_avatar: system_avatar,
|
||||||
force_avatar: system_avatar,
|
is_user: false,
|
||||||
is_user: false,
|
is_system: true,
|
||||||
is_system: true,
|
is_name: true,
|
||||||
is_name: true,
|
mes: renderTemplate("formatting"),
|
||||||
mes: "Generic system message. User `text` parameter to override the contents",
|
},
|
||||||
},
|
macros: {
|
||||||
bookmark_created: {
|
name: systemUserName,
|
||||||
name: systemUserName,
|
force_avatar: system_avatar,
|
||||||
force_avatar: system_avatar,
|
is_user: false,
|
||||||
is_user: false,
|
is_system: true,
|
||||||
is_system: true,
|
is_name: true,
|
||||||
is_name: true,
|
mes: renderTemplate("macros"),
|
||||||
mes: `Bookmark created! Click here to open the bookmark chat: <a class="bookmark_link" file_name="{0}" href="javascript:void(null);">{1}</a>`,
|
},
|
||||||
},
|
welcome:
|
||||||
bookmark_back: {
|
{
|
||||||
name: systemUserName,
|
name: systemUserName,
|
||||||
force_avatar: system_avatar,
|
force_avatar: system_avatar,
|
||||||
is_user: false,
|
is_user: false,
|
||||||
is_system: true,
|
is_system: true,
|
||||||
is_name: true,
|
is_name: true,
|
||||||
mes: `Click here to return to the previous chat: <a class="bookmark_link" file_name="{0}" href="javascript:void(null);">Return</a>`,
|
mes: renderTemplate("welcome"),
|
||||||
},
|
},
|
||||||
};
|
group: {
|
||||||
|
name: systemUserName,
|
||||||
|
force_avatar: system_avatar,
|
||||||
|
is_user: false,
|
||||||
|
is_system: true,
|
||||||
|
is_name: true,
|
||||||
|
is_group: true,
|
||||||
|
mes: "Group chat created. Say 'Hi' to lovely people!",
|
||||||
|
},
|
||||||
|
empty: {
|
||||||
|
name: systemUserName,
|
||||||
|
force_avatar: system_avatar,
|
||||||
|
is_user: false,
|
||||||
|
is_system: true,
|
||||||
|
is_name: true,
|
||||||
|
mes: "No one hears you. <b>Hint:</b> add more members to the group!",
|
||||||
|
},
|
||||||
|
generic: {
|
||||||
|
name: systemUserName,
|
||||||
|
force_avatar: system_avatar,
|
||||||
|
is_user: false,
|
||||||
|
is_system: true,
|
||||||
|
is_name: true,
|
||||||
|
mes: "Generic system message. User `text` parameter to override the contents",
|
||||||
|
},
|
||||||
|
bookmark_created: {
|
||||||
|
name: systemUserName,
|
||||||
|
force_avatar: system_avatar,
|
||||||
|
is_user: false,
|
||||||
|
is_system: true,
|
||||||
|
is_name: true,
|
||||||
|
mes: `Bookmark created! Click here to open the bookmark chat: <a class="bookmark_link" file_name="{0}" href="javascript:void(null);">{1}</a>`,
|
||||||
|
},
|
||||||
|
bookmark_back: {
|
||||||
|
name: systemUserName,
|
||||||
|
force_avatar: system_avatar,
|
||||||
|
is_user: false,
|
||||||
|
is_system: true,
|
||||||
|
is_name: true,
|
||||||
|
mes: `Click here to return to the previous chat: <a class="bookmark_link" file_name="{0}" href="javascript:void(null);">Return</a>`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Register configuration migrations
|
// Register configuration migrations
|
||||||
registerPromptManagerMigration();
|
registerPromptManagerMigration();
|
||||||
@ -551,6 +476,36 @@ $(document).ajaxError(function myErrorHandler(_, xhr) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getUrlSync(url, cache = true) {
|
||||||
|
return $.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: url,
|
||||||
|
cache: cache,
|
||||||
|
async: false
|
||||||
|
}).responseText;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTemplate(templateId, templateData = {}, sanitize = true, localize = true) {
|
||||||
|
try {
|
||||||
|
const templateContent = getUrlSync(`/scripts/templates/${templateId}.html`);
|
||||||
|
const template = Handlebars.compile(templateContent);
|
||||||
|
let result = template(templateData);
|
||||||
|
|
||||||
|
if (sanitize) {
|
||||||
|
result = DOMPurify.sanitize(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localize) {
|
||||||
|
result = applyLocale(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error rendering template", templateId, templateData, err);
|
||||||
|
toastr.error("Check the DevTools console for more information.", "Error rendering template");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function getClientVersion() {
|
async function getClientVersion() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/version');
|
const response = await fetch('/version');
|
||||||
@ -837,6 +792,7 @@ $.ajaxPrefilter((options, originalOptions, xhr) => {
|
|||||||
///// initialization protocol ////////
|
///// initialization protocol ////////
|
||||||
$.get("/csrf-token").then(async (data) => {
|
$.get("/csrf-token").then(async (data) => {
|
||||||
token = data.token;
|
token = data.token;
|
||||||
|
getSystemMessages();
|
||||||
sendSystemMessage(system_message_types.WELCOME);
|
sendSystemMessage(system_message_types.WELCOME);
|
||||||
await readSecretState();
|
await readSecretState();
|
||||||
await getClientVersion();
|
await getClientVersion();
|
||||||
@ -1399,17 +1355,6 @@ function messageFormatting(mes, ch_name, isSystem, isUser) {
|
|||||||
mes = mes.replace(new RegExp(`(^|\n)${ch_name}:`, 'g'), "$1");
|
mes = mes.replace(new RegExp(`(^|\n)${ch_name}:`, 'g'), "$1");
|
||||||
}
|
}
|
||||||
|
|
||||||
//function to hide any <tags> from AI response output
|
|
||||||
/* if (power_user.removeXML && ch_name && !isUser && !isSystem) {
|
|
||||||
//console.log('incoming mes')
|
|
||||||
//console.log(mes)
|
|
||||||
mes = mes.replaceAll(/</g, "<");
|
|
||||||
mes = mes.replaceAll(/>/g, ">");
|
|
||||||
mes = mes.replaceAll(/<<[^>>]+>>/g, "");
|
|
||||||
//console.log('mes after removed <tags>')
|
|
||||||
//console.log(mes)
|
|
||||||
} */
|
|
||||||
|
|
||||||
mes = DOMPurify.sanitize(mes);
|
mes = DOMPurify.sanitize(mes);
|
||||||
|
|
||||||
return mes;
|
return mes;
|
||||||
|
@ -33,7 +33,7 @@ import {
|
|||||||
SECRET_KEYS,
|
SECRET_KEYS,
|
||||||
secret_state,
|
secret_state,
|
||||||
} from "./secrets.js";
|
} from "./secrets.js";
|
||||||
import { debounce, delay, getStringHash } from "./utils.js";
|
import { debounce, delay, getStringHash, waitUntilCondition } from "./utils.js";
|
||||||
import { chat_completion_sources, oai_settings } from "./openai.js";
|
import { chat_completion_sources, oai_settings } from "./openai.js";
|
||||||
|
|
||||||
var NavToggle = document.getElementById("nav-toggle");
|
var NavToggle = document.getElementById("nav-toggle");
|
||||||
@ -717,7 +717,12 @@ export async function initMovingUI() {
|
|||||||
|
|
||||||
// ---------------------------------------------------
|
// ---------------------------------------------------
|
||||||
|
|
||||||
$("document").ready(function () {
|
jQuery(async function () {
|
||||||
|
try {
|
||||||
|
await waitUntilCondition(() => online_status !== undefined, 1000, 10);
|
||||||
|
} catch {
|
||||||
|
console.log('Timeout waiting for online_status');
|
||||||
|
}
|
||||||
|
|
||||||
// initial status check
|
// initial status check
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -28,7 +28,7 @@ async function updateQuickReplyPresetList() {
|
|||||||
if (result.ok) {
|
if (result.ok) {
|
||||||
var data = await result.json();
|
var data = await result.json();
|
||||||
presets = data.quickReplyPresets?.length ? data.quickReplyPresets : [];
|
presets = data.quickReplyPresets?.length ? data.quickReplyPresets : [];
|
||||||
console.log(presets)
|
console.debug('Quick Reply presets', presets);
|
||||||
$("#quickReplyPresets").find('option[value!=""]').remove();
|
$("#quickReplyPresets").find('option[value!=""]').remove();
|
||||||
|
|
||||||
|
|
||||||
@ -284,7 +284,7 @@ async function doQR(_, text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
text = Number(text)
|
text = Number(text)
|
||||||
//use scale starting with 0
|
//use scale starting with 0
|
||||||
//ex: user inputs "/qr 2" >> qr with data-index 1 (but 2nd item displayed) gets triggered
|
//ex: user inputs "/qr 2" >> qr with data-index 1 (but 2nd item displayed) gets triggered
|
||||||
let QRnum = Number(text - 1)
|
let QRnum = Number(text - 1)
|
||||||
if (QRnum <= 0) { QRnum = 0 }
|
if (QRnum <= 0) { QRnum = 0 }
|
||||||
|
75
public/scripts/i18n.js
Normal file
75
public/scripts/i18n.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import { waitUntilCondition } from "./utils.js";
|
||||||
|
|
||||||
|
const storageKey = "language";
|
||||||
|
export const localeData = await fetch("i18n.json").then(response => response.json());
|
||||||
|
|
||||||
|
export function applyLocale(root = document) {
|
||||||
|
const overrideLanguage = localStorage.getItem("language");
|
||||||
|
var language = overrideLanguage || navigator.language || navigator.userLanguage;
|
||||||
|
language = language.toLowerCase();
|
||||||
|
//load the appropriate language file
|
||||||
|
if (localeData.lang.indexOf(language) < 0) language = "en";
|
||||||
|
|
||||||
|
const $root = root instanceof Document ? $(root) : $(new DOMParser().parseFromString(root, "text/html"));
|
||||||
|
|
||||||
|
//find all the elements with `data-i18n` attribute
|
||||||
|
$root.find("[data-i18n]").each(function () {
|
||||||
|
//read the translation from the language data
|
||||||
|
const keys = $(this).data("i18n").split(';'); // Multi-key entries are ; delimited
|
||||||
|
for (const key of keys) {
|
||||||
|
const attributeMatch = key.match(/\[(\S+)\](.+)/); // [attribute]key
|
||||||
|
if (attributeMatch) { // attribute-tagged key
|
||||||
|
const localizedValue = localeData?.[language]?.[attributeMatch[2]];
|
||||||
|
if (localizedValue) {
|
||||||
|
$(this).attr(attributeMatch[1], localizedValue);
|
||||||
|
}
|
||||||
|
} else { // No attribute tag, treat as 'text'
|
||||||
|
const localizedValue = localeData?.[language]?.[key];
|
||||||
|
if (localizedValue) {
|
||||||
|
$(this).text(localizedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (root !== document) {
|
||||||
|
return $root.get(0).body.innerHTML;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addLanguagesToDropdown() {
|
||||||
|
if (!Array.isArray(localeData?.lang)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const lang of localeData.lang) {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = lang;
|
||||||
|
option.innerText = lang;
|
||||||
|
$('#ui_language_select').append(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedLanguage = localStorage.getItem(storageKey);
|
||||||
|
if (selectedLanguage) {
|
||||||
|
$('#ui_language_select').val(selectedLanguage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery(async () => {
|
||||||
|
waitUntilCondition(() => !!localeData);
|
||||||
|
window["applyLocale"] = applyLocale;
|
||||||
|
applyLocale();
|
||||||
|
addLanguagesToDropdown();
|
||||||
|
|
||||||
|
$('#ui_language_select').on('change', async function () {
|
||||||
|
const language = $(this).val();
|
||||||
|
|
||||||
|
if (language) {
|
||||||
|
localStorage.setItem(storageKey, language);
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem(storageKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
});
|
@ -207,7 +207,6 @@ let movingUIPresets = [];
|
|||||||
let context_presets = [];
|
let context_presets = [];
|
||||||
|
|
||||||
const storage_keys = {
|
const storage_keys = {
|
||||||
ui_language: "language",
|
|
||||||
fast_ui_mode: "TavernAI_fast_ui_mode",
|
fast_ui_mode: "TavernAI_fast_ui_mode",
|
||||||
avatar_style: "TavernAI_avatar_style",
|
avatar_style: "TavernAI_avatar_style",
|
||||||
chat_display: "TavernAI_chat_display",
|
chat_display: "TavernAI_chat_display",
|
||||||
@ -1277,26 +1276,6 @@ function doResetPanels() {
|
|||||||
$("#movingUIreset").trigger('click');
|
$("#movingUIreset").trigger('click');
|
||||||
}
|
}
|
||||||
|
|
||||||
function addLanguagesToDropdown() {
|
|
||||||
$.getJSON('i18n.json', function (data) {
|
|
||||||
if (!Array.isArray(data?.lang)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const lang of data.lang) {
|
|
||||||
const option = document.createElement('option');
|
|
||||||
option.value = lang;
|
|
||||||
option.innerText = lang;
|
|
||||||
$('#ui_language_select').append(option);
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedLanguage = localStorage.getItem(storage_keys.ui_language);
|
|
||||||
if (selectedLanguage) {
|
|
||||||
$('#ui_language_select').val(selectedLanguage);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setAvgBG() {
|
function setAvgBG() {
|
||||||
const bgimg = new Image();
|
const bgimg = new Image();
|
||||||
bgimg.src = $('#bg1')
|
bgimg.src = $('#bg1')
|
||||||
@ -2025,18 +2004,6 @@ $(document).ready(() => {
|
|||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#ui_language_select').on('change', async function () {
|
|
||||||
const language = $(this).val();
|
|
||||||
|
|
||||||
if (language) {
|
|
||||||
localStorage.setItem(storage_keys.ui_language, language);
|
|
||||||
} else {
|
|
||||||
localStorage.removeItem(storage_keys.ui_language);
|
|
||||||
}
|
|
||||||
|
|
||||||
location.reload();
|
|
||||||
});
|
|
||||||
|
|
||||||
$(window).on('focus', function () {
|
$(window).on('focus', function () {
|
||||||
browser_has_focus = true;
|
browser_has_focus = true;
|
||||||
});
|
});
|
||||||
@ -2052,5 +2019,4 @@ $(document).ready(() => {
|
|||||||
registerSlashCommand('cut', doMesCut, [], ' <span class="monospace">(requred number)</span> – cuts the specified message from the chat', true, true);
|
registerSlashCommand('cut', doMesCut, [], ' <span class="monospace">(requred number)</span> – cuts the specified message from the chat', true, true);
|
||||||
registerSlashCommand('resetpanels', doResetPanels, ['resetui'], ' – resets UI panels to original state.', true, true);
|
registerSlashCommand('resetpanels', doResetPanels, ['resetui'], ' – resets UI panels to original state.', true, true);
|
||||||
registerSlashCommand('bgcol', setAvgBG, [], ' – WIP test of auto-bg avg coloring', true, true);
|
registerSlashCommand('bgcol', setAvgBG, [], ' – WIP test of auto-bg avg coloring', true, true);
|
||||||
addLanguagesToDropdown();
|
|
||||||
});
|
});
|
||||||
|
21
public/scripts/templates/formatting.html
Normal file
21
public/scripts/templates/formatting.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
Text formatting commands:
|
||||||
|
<ul>
|
||||||
|
<li><tt>*text*</tt> - displays as <i>italics</i></li>
|
||||||
|
<li><tt>**text**</tt> - displays as <b>bold</b></li>
|
||||||
|
<li><tt>***text***</tt> - displays as <b><i>bold italics</i></b></li>
|
||||||
|
<li><tt>```text```</tt> - displays as a code block (new lines allowed between the backticks)</li>
|
||||||
|
</ul>
|
||||||
|
<pre><code> like this</code></pre>
|
||||||
|
<ul>
|
||||||
|
<li><tt>`text`</tt> - displays as <code>inline code</code></li>
|
||||||
|
<li><tt> text</tt> - displays as a blockquote (note the space after >)</li>
|
||||||
|
<blockquote>like this</blockquote>
|
||||||
|
<li><tt># text</tt> - displays as a large header (note the space)</li>
|
||||||
|
<h1>like this</h1>
|
||||||
|
<li><tt>## text</tt> - displays as a medium header (note the space)</li>
|
||||||
|
<h2>like this</h2>
|
||||||
|
<li><tt>### text</tt> - displays as a small header (note the space)</li>
|
||||||
|
<h3>like this</h3>
|
||||||
|
<li><tt>$$ text $$</tt> - renders a LaTeX formula (if enabled)</li>
|
||||||
|
<li><tt>$ text $</tt> - renders an AsciiMath formula (if enabled)</li>
|
||||||
|
</ul>
|
11
public/scripts/templates/help.html
Normal file
11
public/scripts/templates/help.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Hello there! Please select the help topic you would like to learn more about:
|
||||||
|
<ul>
|
||||||
|
<li><a href="#" data-displayHelp="1">Slash Commands</a> (or <tt>/help slash</tt>)</li>
|
||||||
|
<li><a href="#" data-displayHelp="2">Formatting</a> (or <tt>/help format</tt>)</li>
|
||||||
|
<li><a href="#" data-displayHelp="3">Hotkeys</a> (or <tt>/help hotkeys</tt>)</li>
|
||||||
|
<li><a href="#" data-displayHelp="4">{{Macros}}</a> (or <tt>/help macros</tt>)</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
<b>
|
||||||
|
Still got questions left? The <a target="_blank" href="https://docs.sillytavern.app/">Official SillyTavern Documentation Website</a> has much more information!
|
||||||
|
</b>
|
13
public/scripts/templates/hotkeys.html
Normal file
13
public/scripts/templates/hotkeys.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Hotkeys/Keybinds:
|
||||||
|
<ul>
|
||||||
|
<li><tt>Up</tt> = Edit last message in chat</li>
|
||||||
|
<li><tt>Ctrl+Up</tt> = Edit last USER message in chat</li>
|
||||||
|
<li><tt>Left</tt> = swipe left</li>
|
||||||
|
<li><tt>Right</tt> = swipe right (NOTE: swipe hotkeys are disabled when chatbar has something typed into it)</li>
|
||||||
|
<li><tt>Ctrl+Left</tt> = view locally stored variables (in the browser console window)</li>
|
||||||
|
<li><tt>Enter</tt> (with chat bar selected) = send your message to AI</li>
|
||||||
|
<li><tt>Ctrl+Enter</tt> = Regenerate the last AI response</li>
|
||||||
|
<li><tt>Escape</tt> = stop AI response generation</li>
|
||||||
|
<li><tt>Ctrl+Shift+Up</tt> = Scroll to context line</li>
|
||||||
|
<li><tt>Ctrl+Shift+Down</tt> = Scroll chat to bottom</li>
|
||||||
|
</ul>
|
11
public/scripts/templates/macros.html
Normal file
11
public/scripts/templates/macros.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
System-wide Replacement Macros:
|
||||||
|
<ul>
|
||||||
|
<li><tt>{{user}}</tt> - your current Persona username</li>
|
||||||
|
<li><tt>{{char}}</tt> - the Character's name</li>
|
||||||
|
<li><tt>{{input}}</tt> - the user input</li>
|
||||||
|
<li><tt>{{time}}</tt> - the current time</li>
|
||||||
|
<li><tt>{{date}}</tt> - the current date</li>
|
||||||
|
<li><tt>{{idle_duration}}</tt> - the time since the last user message was sent</li>
|
||||||
|
<li><tt>{{random:(args)}}</tt> - returns a random item from the list. (ex: {{random:1,2,3,4}} will return 1 of the 4 numbers at random. Works with text lists too.</li>
|
||||||
|
<li><tt>{{roll:(formula)}}</tt> - rolls a dice. (ex: {{roll:1d6}} will roll a 6-sided dice and return a number between 1 and 6)</li>
|
||||||
|
</ul>
|
72
public/scripts/templates/welcome.html
Normal file
72
public/scripts/templates/welcome.html
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<h3>
|
||||||
|
<span id="version_display_welcome">SillyTavern</span>
|
||||||
|
<div id="version_display_welcome"></div>
|
||||||
|
</h3>
|
||||||
|
<a href="https://docs.sillytavern.app/usage/update/"" target=" _blank">
|
||||||
|
Want to update?
|
||||||
|
</a>
|
||||||
|
<hr>
|
||||||
|
<h3>How to start chatting?</h3>
|
||||||
|
<ol>
|
||||||
|
<li>Click <code><i class="fa-solid fa-plug"></i></code> and select a <a href="https://docs.sillytavern.app/usage/api-connections/" target="_blank">Chat API</a>.</li>
|
||||||
|
<li>Click <code><i class="fa-solid fa-address-card"></i></code> and pick a character</li>
|
||||||
|
</ol>
|
||||||
|
<hr>
|
||||||
|
<h3>
|
||||||
|
Want more characters?
|
||||||
|
</h3>
|
||||||
|
<i>
|
||||||
|
Not controlled by SillyTavern team.
|
||||||
|
</i>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a target="_blank" href="https://discord.gg/pygmalionai">
|
||||||
|
Pygmalion AI Discord
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a target="_blank" href="https://chub.ai/">
|
||||||
|
Chub (NSFW)
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<hr>
|
||||||
|
<h3>Confused or lost?</h3>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="note-link-span">?</span> - click these icons!
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Enter <code>/?</code> in the chat bar
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a target="_blank" href="https://docs.sillytavern.app/">
|
||||||
|
SillyTavern Documentation Site
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a target="_blank" href="https://docs.sillytavern.app/extras/installation/">
|
||||||
|
Extras Installation Guide
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h3>Still have questions?</h3>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a target="_blank" href="https://discord.gg/RZdyAEUPvj">
|
||||||
|
Join the SillyTavern Discord
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a target="_blank" href="https://github.com/SillyTavern/SillyTavern/issues">
|
||||||
|
Post a GitHub issue
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a target="_blank" href="https://github.com/SillyTavern/SillyTavern#questions-or-suggestions">
|
||||||
|
Contact the developers
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
Reference in New Issue
Block a user