Merge branch 'staging' of https://github.com/Cohee1207/SillyTavern into staging
This commit is contained in:
commit
0bc6f369b8
|
@ -90,6 +90,7 @@
|
||||||
<script type="module" src="scripts/setting-search.js"></script>
|
<script type="module" src="scripts/setting-search.js"></script>
|
||||||
<script type="module" src="scripts/bulk-edit.js"></script>
|
<script type="module" src="scripts/bulk-edit.js"></script>
|
||||||
<script type="module" src="scripts/cfg-scale.js"></script>
|
<script type="module" src="scripts/cfg-scale.js"></script>
|
||||||
|
<script type="module" src="scripts/chats.js"></script>
|
||||||
|
|
||||||
<title>SillyTavern</title>
|
<title>SillyTavern</title>
|
||||||
</head>
|
</head>
|
||||||
|
@ -4385,6 +4386,7 @@
|
||||||
<div class="flex-container flex1 alignitemscenter">
|
<div class="flex-container flex1 alignitemscenter">
|
||||||
<div class="flex-container alignItemsBaseline">
|
<div class="flex-container alignItemsBaseline">
|
||||||
<span class="name_text">${characterName}</span>
|
<span class="name_text">${characterName}</span>
|
||||||
|
<i class="mes_ghost fa-solid fa-ghost" title="This message is invisible for the AI" data-i18n="[title]This message is invisible for the AI"></i>
|
||||||
<small class="timestamp"></small>
|
<small class="timestamp"></small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4396,6 +4398,8 @@
|
||||||
<div title="Generate Image" class="sd_message_gen fa-solid fa-paintbrush" data-i18n="[title]Generate Image"></div>
|
<div title="Generate Image" class="sd_message_gen fa-solid fa-paintbrush" data-i18n="[title]Generate Image"></div>
|
||||||
<div title="Narrate" class="mes_narrate fa-solid fa-bullhorn" data-i18n="[title]Narrate"></div>
|
<div title="Narrate" class="mes_narrate fa-solid fa-bullhorn" data-i18n="[title]Narrate"></div>
|
||||||
<div title="Prompt" class="mes_prompt fa-solid fa-square-poll-horizontal " data-i18n="[title]Prompt"></div>
|
<div title="Prompt" class="mes_prompt fa-solid fa-square-poll-horizontal " data-i18n="[title]Prompt"></div>
|
||||||
|
<div title="Exclude message from prompts" class="mes_hide fa-solid fa-eye" data-i18n="[title]Exclude message from prompts"></div>
|
||||||
|
<div title="Include message in prompts" class="mes_unhide fa-solid fa-eye-slash" data-i18n="[title]Include message in prompts"></div>
|
||||||
<div title="Create bookmark" class="mes_create_bookmark fa-regular fa-solid fa-book-bookmark" data-i18n="[title]Create Bookmark"></div>
|
<div title="Create bookmark" class="mes_create_bookmark fa-regular fa-solid fa-book-bookmark" data-i18n="[title]Create Bookmark"></div>
|
||||||
<div title="Create branch" class="mes_create_branch fa-regular fa-code-branch" data-i18n="[title]Create Branch"></div>
|
<div title="Create branch" class="mes_create_branch fa-regular fa-code-branch" data-i18n="[title]Create Branch"></div>
|
||||||
<div title="Copy" class="mes_copy fa-solid fa-copy " data-i18n="[title]Copy"></div>
|
<div title="Copy" class="mes_copy fa-solid fa-copy " data-i18n="[title]Copy"></div>
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
// Move chat functions here from script.js (eventually)
|
||||||
|
|
||||||
|
import {
|
||||||
|
chat,
|
||||||
|
getCurrentChatId,
|
||||||
|
hideSwipeButtons,
|
||||||
|
saveChatConditional,
|
||||||
|
showSwipeButtons,
|
||||||
|
} from "../script.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark message as hidden (system message).
|
||||||
|
* @param {number} messageId Message ID
|
||||||
|
* @param {JQuery<Element>} messageBlock Message UI element
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function hideChatMessage(messageId, messageBlock) {
|
||||||
|
const chatId = getCurrentChatId();
|
||||||
|
|
||||||
|
if (!chatId || isNaN(messageId)) return;
|
||||||
|
|
||||||
|
const message = chat[messageId];
|
||||||
|
|
||||||
|
if (!message) return;
|
||||||
|
|
||||||
|
message.is_system = true;
|
||||||
|
messageBlock.attr('is_system', String(true));
|
||||||
|
|
||||||
|
// Reload swipes. Useful when a last message is hidden.
|
||||||
|
hideSwipeButtons();
|
||||||
|
showSwipeButtons();
|
||||||
|
|
||||||
|
await saveChatConditional();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark message as visible (non-system message).
|
||||||
|
* @param {number} messageId Message ID
|
||||||
|
* @param {JQuery<Element>} messageBlock Message UI element
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function unhideChatMessage(messageId, messageBlock) {
|
||||||
|
const chatId = getCurrentChatId();
|
||||||
|
|
||||||
|
if (!chatId || isNaN(messageId)) return;
|
||||||
|
|
||||||
|
const message = chat[messageId];
|
||||||
|
|
||||||
|
if (!message) return;
|
||||||
|
|
||||||
|
message.is_system = false;
|
||||||
|
messageBlock.attr('is_system', String(false));
|
||||||
|
|
||||||
|
// Reload swipes. Useful when a last message is hidden.
|
||||||
|
hideSwipeButtons();
|
||||||
|
showSwipeButtons();
|
||||||
|
|
||||||
|
await saveChatConditional();
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery(function() {
|
||||||
|
$(document).on('click', '.mes_hide', async function() {
|
||||||
|
const messageBlock = $(this).closest('.mes');
|
||||||
|
const messageId = Number(messageBlock.attr('mesid'));
|
||||||
|
await hideChatMessage(messageId, messageBlock);
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('click', '.mes_unhide', async function() {
|
||||||
|
const messageBlock = $(this).closest('.mes');
|
||||||
|
const messageId = Number(messageBlock.attr('mesid'));
|
||||||
|
await unhideChatMessage(messageId, messageBlock);
|
||||||
|
});
|
||||||
|
})
|
|
@ -119,19 +119,9 @@ const promptTemplates = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const helpString = [
|
const helpString = [
|
||||||
`${m('(argument)')} – requests SD to make an image. Supported arguments:`,
|
`${m('(argument)')} – requests SD to make an image. Supported arguments: ${m(j(Object.values(triggerWords).flat()))}.`,
|
||||||
'<ul>',
|
`Anything else would trigger a "free mode" to make SD generate whatever you prompted. Example: '/sd apple tree' would generate a picture of an apple tree.`,
|
||||||
`<li>${m(j(triggerWords[generationMode.CHARACTER]))} – AI character full body selfie</li>`,
|
].join(' ');
|
||||||
`<li>${m(j(triggerWords[generationMode.FACE]))} – AI character face-only selfie</li>`,
|
|
||||||
`<li>${m(j(triggerWords[generationMode.USER]))} – user character full body selfie</li>`,
|
|
||||||
`<li>${m(j(triggerWords[generationMode.SCENARIO]))} – visual recap of the whole chat scenario</li>`,
|
|
||||||
`<li>${m(j(triggerWords[generationMode.NOW]))} – visual recap of the last chat message</li>`,
|
|
||||||
`<li>${m(j(triggerWords[generationMode.RAW_LAST]))} – visual recap of the last chat message with no summary</li>`,
|
|
||||||
`<li>${m(j(triggerWords[generationMode.BACKGROUND]))} – generate a background for this chat based on the chat's context</li>`,
|
|
||||||
'</ul>',
|
|
||||||
`Anything else would trigger a "free mode" to make SD generate whatever you prompted.<Br>
|
|
||||||
example: '/sd apple tree' would generate a picture of an apple tree.`,
|
|
||||||
].join('<br>');
|
|
||||||
|
|
||||||
const defaultPrefix = 'best quality, absurdres, aesthetic,';
|
const defaultPrefix = 'best quality, absurdres, aesthetic,';
|
||||||
const defaultNegative = 'lowres, bad anatomy, bad hands, text, error, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry';
|
const defaultNegative = 'lowres, bad anatomy, bad hands, text, error, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry';
|
||||||
|
|
|
@ -31,6 +31,7 @@ import { getRegexedString, regex_placement } from "./extensions/regex/engine.js"
|
||||||
import { chat_styles, power_user } from "./power-user.js";
|
import { chat_styles, power_user } from "./power-user.js";
|
||||||
import { autoSelectPersona } from "./personas.js";
|
import { autoSelectPersona } from "./personas.js";
|
||||||
import { getContext } from "./extensions.js";
|
import { getContext } from "./extensions.js";
|
||||||
|
import { hideChatMessage, unhideChatMessage } from "./chats.js";
|
||||||
export {
|
export {
|
||||||
executeSlashCommands,
|
executeSlashCommands,
|
||||||
registerSlashCommand,
|
registerSlashCommand,
|
||||||
|
@ -40,7 +41,7 @@ export {
|
||||||
class SlashCommandParser {
|
class SlashCommandParser {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.commands = {};
|
this.commands = {};
|
||||||
this.helpStrings = [];
|
this.helpStrings = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
addCommand(command, callback, aliases, helpString = '', interruptsGeneration = false, purgeFromMessage = true) {
|
addCommand(command, callback, aliases, helpString = '', interruptsGeneration = false, purgeFromMessage = true) {
|
||||||
|
@ -63,7 +64,7 @@ class SlashCommandParser {
|
||||||
let aliasesString = `(alias: ${aliases.map(x => `<span class="monospace">/${x}</span>`).join(', ')})`;
|
let aliasesString = `(alias: ${aliases.map(x => `<span class="monospace">/${x}</span>`).join(', ')})`;
|
||||||
stringBuilder += aliasesString;
|
stringBuilder += aliasesString;
|
||||||
}
|
}
|
||||||
this.helpStrings.push(stringBuilder);
|
this.helpStrings[command] = stringBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse(text) {
|
parse(text) {
|
||||||
|
@ -107,7 +108,12 @@ class SlashCommandParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
getHelpString() {
|
getHelpString() {
|
||||||
const listItems = this.helpStrings.map(x => `<li>${x}</li>`).join('\n');
|
const listItems = Object
|
||||||
|
.entries(this.helpStrings)
|
||||||
|
.sort((a, b) => a[0].localeCompare(b[0]))
|
||||||
|
.map(x => x[1])
|
||||||
|
.map(x => `<li>${x}</li>`)
|
||||||
|
.join('\n');
|
||||||
return `<p>Slash commands:</p><ol>${listItems}</ol>
|
return `<p>Slash commands:</p><ol>${listItems}</ol>
|
||||||
<small>Slash commands can be batched into a single input by adding a pipe character | at the end, and then writing a new slash command.</small>
|
<small>Slash commands can be batched into a single input by adding a pipe character | at the end, and then writing a new slash command.</small>
|
||||||
<ul><li><small>Example:</small><code>/cut 1 | /sys Hello, | /continue</code></li>
|
<ul><li><small>Example:</small><code>/cut 1 | /sys Hello, | /continue</code></li>
|
||||||
|
@ -138,6 +144,8 @@ parser.addCommand('ask', askCharacter, [], '<span class="monospace">(prompt)</sp
|
||||||
parser.addCommand('delname', deleteMessagesByNameCallback, ['cancel'], '<span class="monospace">(name)</span> – deletes all messages attributed to a specified name', true, true);
|
parser.addCommand('delname', deleteMessagesByNameCallback, ['cancel'], '<span class="monospace">(name)</span> – deletes all messages attributed to a specified name', true, true);
|
||||||
parser.addCommand('send', sendUserMessageCallback, ['add'], '<span class="monospace">(text)</span> – adds a user message to the chat log without triggering a generation', true, true);
|
parser.addCommand('send', sendUserMessageCallback, ['add'], '<span class="monospace">(text)</span> – adds a user message to the chat log without triggering a generation', true, true);
|
||||||
parser.addCommand('trigger', triggerGroupMessageCallback, [], '<span class="monospace">(member index or name)</span> – triggers a message generation for the specified group member', true, true);
|
parser.addCommand('trigger', triggerGroupMessageCallback, [], '<span class="monospace">(member index or name)</span> – triggers a message generation for the specified group member', true, true);
|
||||||
|
parser.addCommand('hide', hideMessageCallback, [], '<span class="monospace">(message index)</span> – hides a chat message from the prompt', true, true);
|
||||||
|
parser.addCommand('unhide', unhideMessageCallback, [], '<span class="monospace">(message index)</span> – unhides a message from the prompt', true, true);
|
||||||
|
|
||||||
const NARRATOR_NAME_KEY = 'narrator_name';
|
const NARRATOR_NAME_KEY = 'narrator_name';
|
||||||
const NARRATOR_NAME_DEFAULT = 'System';
|
const NARRATOR_NAME_DEFAULT = 'System';
|
||||||
|
@ -225,6 +233,40 @@ async function askCharacter(_, text) {
|
||||||
eventSource.on(event_types.CHARACTER_MESSAGE_RENDERED, restoreCharacter);
|
eventSource.on(event_types.CHARACTER_MESSAGE_RENDERED, restoreCharacter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function hideMessageCallback(_, arg) {
|
||||||
|
if (!arg) {
|
||||||
|
console.warn('WARN: No argument provided for /hide command');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageId = Number(arg);
|
||||||
|
const messageBlock = $(`.mes[mesid="${messageId}"]`);
|
||||||
|
|
||||||
|
if (!messageBlock.length) {
|
||||||
|
console.warn(`WARN: No message found with ID ${messageId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await hideChatMessage(messageId, messageBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function unhideMessageCallback(_, arg) {
|
||||||
|
if (!arg) {
|
||||||
|
console.warn('WARN: No argument provided for /unhide command');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageId = Number(arg);
|
||||||
|
const messageBlock = $(`.mes[mesid="${messageId}"]`);
|
||||||
|
|
||||||
|
if (!messageBlock.length) {
|
||||||
|
console.warn(`WARN: No message found with ID ${messageId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await unhideChatMessage(messageId, messageBlock);
|
||||||
|
}
|
||||||
|
|
||||||
async function triggerGroupMessageCallback(_, arg) {
|
async function triggerGroupMessageCallback(_, arg) {
|
||||||
if (!selected_group) {
|
if (!selected_group) {
|
||||||
toastr.warning("Cannot run this command outside of a group chat.");
|
toastr.warning("Cannot run this command outside of a group chat.");
|
||||||
|
@ -680,3 +722,42 @@ function executeSlashCommands(text) {
|
||||||
|
|
||||||
return { interrupt, newText };
|
return { interrupt, newText };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setSlashCommandAutocomplete(textarea) {
|
||||||
|
textarea.autocomplete({
|
||||||
|
source: (input, output) => {
|
||||||
|
// Only show for slash commands and if there's no space
|
||||||
|
if (!input.term.startsWith('/') || input.term.includes(' ')) {
|
||||||
|
output([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const slashCommand = input.term.toLowerCase().substring(1); // Remove the slash
|
||||||
|
const result = Object
|
||||||
|
.keys(parser.helpStrings) // Get all slash commands
|
||||||
|
.filter(x => x.startsWith(slashCommand)) // Filter by the input
|
||||||
|
.sort((a, b) => a.localeCompare(b)) // Sort alphabetically
|
||||||
|
// .slice(0, 20) // Limit to 20 results
|
||||||
|
.map(x => ({ label: parser.helpStrings[x], value: `/${x} ` })); // Map to the help string
|
||||||
|
|
||||||
|
output(result); // Return the results
|
||||||
|
},
|
||||||
|
select: (e, u) => {
|
||||||
|
// unfocus the input
|
||||||
|
$(e.target).val(u.item.value);
|
||||||
|
},
|
||||||
|
minLength: 1,
|
||||||
|
position: { my: "left bottom", at: "left top", collision: "none" },
|
||||||
|
});
|
||||||
|
|
||||||
|
textarea.autocomplete("instance")._renderItem = function (ul, item) {
|
||||||
|
const width = $(textarea).innerWidth();
|
||||||
|
const content = $('<div></div>').html(item.label);
|
||||||
|
return $("<li>").width(width).append(content).appendTo(ul);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery(function () {
|
||||||
|
const textarea = $('#send_textarea');
|
||||||
|
setSlashCommandAutocomplete(textarea);
|
||||||
|
})
|
||||||
|
|
|
@ -218,6 +218,11 @@ table.responsiveTable {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mes[is_system="true"] .avatar {
|
||||||
|
opacity: 0.9;
|
||||||
|
filter: grayscale(25%);
|
||||||
|
}
|
||||||
|
|
||||||
.mes_text table {
|
.mes_text table {
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
|
@ -304,10 +309,23 @@ table.responsiveTable {
|
||||||
|
|
||||||
.mes_translate,
|
.mes_translate,
|
||||||
.sd_message_gen,
|
.sd_message_gen,
|
||||||
|
.mes_ghost,
|
||||||
.mes_narrate {
|
.mes_narrate {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mes[is_system="true"] .mes_hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mes[is_system="false"] .mes_unhide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mes[is_system="true"] .mes_ghost {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
small {
|
small {
|
||||||
color: var(--grey70);
|
color: var(--grey70);
|
||||||
}
|
}
|
||||||
|
@ -2802,7 +2820,7 @@ body .ui-widget-content li {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
transition: all 200ms;
|
transition: opacity 200ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
body .ui-widget-content li:hover {
|
body .ui-widget-content li:hover {
|
||||||
|
@ -3645,4 +3663,4 @@ a {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue