mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-01-31 19:45:35 +01:00
Merge branch 'SillyTavern:staging' into staging
This commit is contained in:
commit
7437b23fa2
@ -128,14 +128,14 @@
|
||||
"max_context_unlocked": false,
|
||||
"prefer_character_prompt": true,
|
||||
"prefer_character_jailbreak": true,
|
||||
"continue_on_send": false,
|
||||
"quick_continue": false,
|
||||
"trim_spaces": true,
|
||||
"relaxed_api_urls": false,
|
||||
"default_instruct": "",
|
||||
"instruct": {
|
||||
"enabled": false,
|
||||
"preset": "🧙 Roleplay",
|
||||
"system_prompt": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}.\n\nAvoid repetition, don't loop. Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions.\n\n### Input:",
|
||||
"preset": "Roleplay",
|
||||
"system_prompt": "Avoid repetition, don't loop. Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions.",
|
||||
"input_sequence": "\n### Instruction:",
|
||||
"output_sequence": "\n### Response:",
|
||||
"last_output_sequence": "\n### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):",
|
||||
@ -150,7 +150,7 @@
|
||||
},
|
||||
"context": {
|
||||
"preset": "Default",
|
||||
"story_string": "{{#if system}}{{system}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}",
|
||||
"story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}",
|
||||
"chat_start": "***",
|
||||
"example_separator": "***"
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Default",
|
||||
"story_string": "{{#if system}}{{system}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}",
|
||||
"story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}",
|
||||
"chat_start": "***",
|
||||
"example_separator": "***"
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Pygmalion",
|
||||
"story_string": "{{#if system}}{{system}}\n{{/if}}{{#if description}}{{{char}}}'s Persona: {{description}}\n{{/if}}{{#if personality}}Personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}",
|
||||
"story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{{char}}}'s Persona: {{description}}\n{{/if}}{{#if personality}}Personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}",
|
||||
"chat_start": "<START>",
|
||||
"example_separator": "<START>"
|
||||
}
|
||||
|
6
public/context/Roleplay.json
Normal file
6
public/context/Roleplay.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "Roleplay",
|
||||
"story_string": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}.\n\n{{#if system}}{{system}}\n\n{{/if}}### Input:\n{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}",
|
||||
"chat_start": "### New Roleplay:",
|
||||
"example_separator": "### New Roleplay:"
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-proxy-for-tavern",
|
||||
"story_string": "## {{char}}\n- You're \"{{char}}\" in this never-ending roleplay with \"{{user}}\".\n### Input:\n{{#if system}}{{system}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}### Response:\n(OOC) Understood. I will take this info into account for the roleplay. (end OOC)",
|
||||
"story_string": "## {{char}}\n- You're \"{{char}}\" in this never-ending roleplay with \"{{user}}\".\n### Input:\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}### Response:\n(OOC) Understood. I will take this info into account for the roleplay. (end OOC)",
|
||||
"chat_start": "### New Roleplay:",
|
||||
"example_separator": "### New Roleplay:"
|
||||
}
|
||||
|
1114
public/i18n.json
1114
public/i18n.json
File diff suppressed because it is too large
Load Diff
@ -2816,10 +2816,10 @@
|
||||
<input id="prefer_character_jailbreak" type="checkbox" />
|
||||
<span data-i18n="Prefer Character Card Jailbreak">Prefer Char. JB</span>
|
||||
</label>
|
||||
<label class="checkbox_label" for="continue_on_send">
|
||||
<input id="continue_on_send" type="checkbox" />
|
||||
<label class="checkbox_label" for="quick_continue">
|
||||
<input id="quick_continue" type="checkbox" />
|
||||
<span data-i18n="Press Send to continue">
|
||||
Press "Send" to continue
|
||||
Show quick "Continue" button
|
||||
</span>
|
||||
</label>
|
||||
<label class="checkbox_label" for="auto-load-chat-checkbox">
|
||||
@ -4202,7 +4202,8 @@
|
||||
<div id="mes_stop" title="Abort request" class="mes_stop" data-i18n="[title]Abort request">
|
||||
<i class="fa-solid fa-circle-stop"></i>
|
||||
</div>
|
||||
<div id="send_but" class="fa-solid fa-paper-plane" title="Send a message" data-i18n="[title]Send a message"></div>
|
||||
<div id="mes_continue" class="fa-fw fa-solid fa-arrow-right displayNone" title="Continue the last message" data-i18n="[title]Continue the last message"></div>
|
||||
<div id="send_but" class="fa-solid fa-paper-plane displayNone" title="Send a message" data-i18n="[title]Send a message"></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "🧙 Roleplay",
|
||||
"system_prompt": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}.\n\nAvoid repetition, don't loop. Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions.\n\n### Input:",
|
||||
"name": "Roleplay",
|
||||
"system_prompt": "Avoid repetition, don't loop. Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions.",
|
||||
"input_sequence": "\n### Instruction:",
|
||||
"output_sequence": "\n### Response:",
|
||||
"last_output_sequence": "\n### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):",
|
342
public/script.js
342
public/script.js
@ -129,6 +129,7 @@ import {
|
||||
getCharaFilename,
|
||||
isDigitsOnly,
|
||||
PAGINATION_TEMPLATE,
|
||||
waitUntilCondition,
|
||||
} from "./scripts/utils.js";
|
||||
|
||||
import { extension_settings, getContext, loadExtensionSettings, processExtensionHelpers, registerExtensionHelper, runGenerationInterceptors, saveMetadataDebounced } from "./scripts/extensions.js";
|
||||
@ -314,6 +315,8 @@ let safetychat = [
|
||||
mes: "You deleted a character/chat and arrived back here for safety reasons! Pick another character!",
|
||||
},
|
||||
];
|
||||
let chatSaveTimeout;
|
||||
export let isChatSaving = false;
|
||||
let chat_create_date = 0;
|
||||
let firstRun = false;
|
||||
|
||||
@ -350,7 +353,6 @@ let scrollLock = false;
|
||||
const durationSaveEdit = 1000;
|
||||
const saveSettingsDebounced = debounce(() => saveSettings(), durationSaveEdit);
|
||||
export const saveCharacterDebounced = debounce(() => $("#create_button").trigger('click'), durationSaveEdit);
|
||||
const saveChatDebounced = debounce(() => saveChatConditional(), durationSaveEdit);
|
||||
|
||||
const system_message_types = {
|
||||
HELP: "help",
|
||||
@ -623,7 +625,6 @@ let is_api_button_press_novel = false;
|
||||
let api_use_mancer_webui = false;
|
||||
|
||||
let is_send_press = false; //Send generation
|
||||
let add_mes_without_animation = false;
|
||||
|
||||
let this_del_mes = 0;
|
||||
|
||||
@ -821,6 +822,11 @@ export function selectCharacterById(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isChatSaving) {
|
||||
toastr.info("Please wait until the chat is saved before switching characters.", "Your chat is still saving...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected_group && is_group_generating) {
|
||||
return;
|
||||
}
|
||||
@ -1884,24 +1890,19 @@ function cleanGroupMessage(getMessage) {
|
||||
return getMessage;
|
||||
}
|
||||
|
||||
function getPersonaDescription(storyString) {
|
||||
function addPersonaDescriptionExtensionPrompt() {
|
||||
if (!power_user.persona_description) {
|
||||
return storyString;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (power_user.persona_description_position) {
|
||||
case persona_description_positions.BEFORE_CHAR:
|
||||
case persona_description_positions.AFTER_CHAR:
|
||||
return storyString;
|
||||
default:
|
||||
if (shouldWIAddPrompt) {
|
||||
const originalAN = extension_prompts[NOTE_MODULE_NAME].value
|
||||
const ANWithDesc = power_user.persona_description_position === persona_description_positions.TOP_AN
|
||||
? `${power_user.persona_description}\n${originalAN}`
|
||||
: `${originalAN}\n${power_user.persona_description}`;
|
||||
setExtensionPrompt(NOTE_MODULE_NAME, ANWithDesc, chat_metadata[metadata_keys.position], chat_metadata[metadata_keys.depth]);
|
||||
}
|
||||
return storyString;
|
||||
const promptPositions = [persona_description_positions.BOTTOM_AN, persona_description_positions.TOP_AN];
|
||||
|
||||
if (promptPositions.includes(power_user.persona_description_position) && shouldWIAddPrompt) {
|
||||
const originalAN = extension_prompts[NOTE_MODULE_NAME].value
|
||||
const ANWithDesc = power_user.persona_description_position === persona_description_positions.TOP_AN
|
||||
? `${power_user.persona_description}\n${originalAN}`
|
||||
: `${originalAN}\n${power_user.persona_description}`;
|
||||
setExtensionPrompt(NOTE_MODULE_NAME, ANWithDesc, chat_metadata[metadata_keys.position], chat_metadata[metadata_keys.depth]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2287,6 +2288,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
setCharacterName('');
|
||||
} else {
|
||||
console.log('No enabled members found');
|
||||
is_send_press = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2318,10 +2320,6 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
}
|
||||
}
|
||||
|
||||
if (!type && !textareaText && power_user.continue_on_send && !selected_group && chat.length && !chat[chat.length - 1]['is_user']) {
|
||||
type = 'continue';
|
||||
}
|
||||
|
||||
const isContinue = type == 'continue';
|
||||
|
||||
if (!dryRun) {
|
||||
@ -2405,18 +2403,6 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
|
||||
console.log(`Core/all messages: ${coreChat.length}/${chat.length}`);
|
||||
|
||||
const storyStringParams = {
|
||||
description: charDescription,
|
||||
personality: charPersonality,
|
||||
persona: personaDescription,
|
||||
scenario: Scenario,
|
||||
system: isInstruct ? systemPrompt : '',
|
||||
char: name2,
|
||||
user: name1,
|
||||
};
|
||||
|
||||
let storyString = renderStoryString(storyStringParams);
|
||||
|
||||
// kingbri MARK: - Make sure the prompt bias isn't the same as the user bias
|
||||
if ((promptBias && !isUserPromptBias) || power_user.always_force_name2 || is_pygmalion) {
|
||||
force_name2 = true;
|
||||
@ -2437,10 +2423,15 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
break;
|
||||
}
|
||||
|
||||
chat2[i] = formatMessageHistoryItem(coreChat[j], isInstruct);
|
||||
chat2[i] = formatMessageHistoryItem(coreChat[j], isInstruct, false);
|
||||
|
||||
// Do not suffix the message for continuation
|
||||
if (i === 0 && isContinue) {
|
||||
if (isInstruct) {
|
||||
// Reformat with the last output line (if any)
|
||||
chat2[i] = formatMessageHistoryItem(coreChat[j], isInstruct, true);
|
||||
}
|
||||
|
||||
chat2[i] = chat2[i].slice(0, chat2[i].lastIndexOf(coreChat[j].mes) + coreChat[j].mes.length);
|
||||
continue_mag = coreChat[j].mes;
|
||||
}
|
||||
@ -2462,22 +2453,32 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
}
|
||||
|
||||
// Extension added strings
|
||||
|
||||
// Set non-WI AN
|
||||
setFloatingPrompt();
|
||||
// Add WI to prompt (and also inject WI to AN value via hijack)
|
||||
let { worldInfoString, worldInfoBefore, worldInfoAfter } = await getWorldInfoPrompt(chat2, this_max_context);
|
||||
// Add persona description to prompt
|
||||
storyString = getPersonaDescription(storyString);
|
||||
addPersonaDescriptionExtensionPrompt();
|
||||
// Call combined AN into Generate
|
||||
let allAnchors = getAllExtensionPrompts();
|
||||
const afterScenarioAnchor = getExtensionPrompt(extension_prompt_types.AFTER_SCENARIO);
|
||||
let zeroDepthAnchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, 0, ' ');
|
||||
|
||||
// Pre-format the World Info into the story string
|
||||
if (main_api !== 'openai') {
|
||||
storyString = worldInfoBefore + storyString + worldInfoAfter;
|
||||
}
|
||||
const storyStringParams = {
|
||||
description: charDescription,
|
||||
personality: charPersonality,
|
||||
persona: personaDescription,
|
||||
scenario: Scenario,
|
||||
system: isInstruct ? systemPrompt : '',
|
||||
char: name2,
|
||||
user: name1,
|
||||
wiBefore: worldInfoBefore,
|
||||
wiAfter: worldInfoAfter,
|
||||
loreBefore: worldInfoBefore,
|
||||
loreAfter: worldInfoAfter,
|
||||
};
|
||||
|
||||
const storyString = renderStoryString(storyStringParams);
|
||||
|
||||
if (main_api === 'openai') {
|
||||
message_already_generated = ''; // OpenAI doesn't have multigen
|
||||
@ -2599,16 +2600,9 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
return;
|
||||
}
|
||||
|
||||
if (i === arrMes.length - 1 && !item.trim().startsWith(name1 + ":")) {
|
||||
//if (textareaText == "") {
|
||||
// Cohee: I think this was added to allow the model to continue
|
||||
// where it left off by removing the trailing newline at the end
|
||||
// that was added by chat2 generator. This causes problems with
|
||||
// instruct mode that could not have a trailing newline. So we're
|
||||
// removing a newline ONLY at the end of the string if it exists.
|
||||
// Cohee: I'm not even sure what this is for anymore
|
||||
if (i === arrMes.length - 1 && type !== 'continue') {
|
||||
item = item.replace(/\n?$/, '');
|
||||
//item = item.substr(0, item.length - 1);
|
||||
//}
|
||||
}
|
||||
if (is_pygmalion && !isInstruct) {
|
||||
if (item.trim().startsWith(name1)) {
|
||||
@ -2654,7 +2648,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
// Add quiet generation prompt at depth 0
|
||||
if (quiet_prompt && quiet_prompt.length) {
|
||||
const name = is_pygmalion ? 'You' : name1;
|
||||
const quietAppend = isInstruct ? formatInstructModeChat(name, quiet_prompt, false, true, false, name1, name2) : `\n${name}: ${quiet_prompt}`;
|
||||
const quietAppend = isInstruct ? formatInstructModeChat(name, quiet_prompt, false, true, '', name1, name2, false) : `\n${name}: ${quiet_prompt}`;
|
||||
lastMesString += quietAppend;
|
||||
// Bail out early
|
||||
return lastMesString;
|
||||
@ -2700,6 +2694,11 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
promptCache = promptCache.replace(promptBias, '');
|
||||
}
|
||||
|
||||
// Add a space if prompt cache doesn't start with one
|
||||
if (!/^\s/.test(promptCache) && !isInstruct) {
|
||||
promptCache = ' ' + promptCache;
|
||||
}
|
||||
|
||||
return promptCache;
|
||||
}
|
||||
|
||||
@ -2823,7 +2822,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
let finalPromt = getCombinedPrompt(false);
|
||||
|
||||
// Include the entire guidance scale object
|
||||
const cfgValues = cfgGuidanceScale && cfgGuidanceScale?.value !== 1 ? ({guidanceScale: cfgGuidanceScale, negativePrompt: negativePrompt }) : null;
|
||||
const cfgValues = cfgGuidanceScale && cfgGuidanceScale?.value !== 1 ? ({ guidanceScale: cfgGuidanceScale, negativePrompt: negativePrompt }) : null;
|
||||
|
||||
let this_amount_gen = Number(amount_gen); // how many tokens the AI will be requested to generate
|
||||
let this_settings = koboldai_settings[koboldai_setting_names[preset_settings]];
|
||||
@ -2880,6 +2879,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
cyclePrompt: cyclePrompt,
|
||||
systemPromptOverride: systemPrompt,
|
||||
jailbreakPromptOverride: jailbreakPrompt,
|
||||
personaDescription: personaDescription
|
||||
}, dryRun);
|
||||
generate_data = { prompt: prompt };
|
||||
|
||||
@ -3216,7 +3216,12 @@ export function getBiasStrings(textareaText, type) {
|
||||
return { messageBias, promptBias, isUserPromptBias };
|
||||
}
|
||||
|
||||
function formatMessageHistoryItem(chatItem, isInstruct) {
|
||||
/**
|
||||
* @param {Object} chatItem Message history item.
|
||||
* @param {boolean} isInstruct Whether instruct mode is enabled.
|
||||
* @param {boolean} forceLastOutputSequence Whether to force the last output sequence for instruct mode.
|
||||
*/
|
||||
function formatMessageHistoryItem(chatItem, isInstruct, forceLastOutputSequence) {
|
||||
const isNarratorType = chatItem?.extra?.type === system_message_types.NARRATOR;
|
||||
const characterName = (selected_group || chatItem.force_avatar) ? chatItem.name : name2;
|
||||
const itemName = chatItem.is_user ? chatItem['name'] : characterName;
|
||||
@ -3225,7 +3230,7 @@ function formatMessageHistoryItem(chatItem, isInstruct) {
|
||||
let textResult = shouldPrependName ? `${itemName}: ${chatItem.mes}\n` : `${chatItem.mes}\n`;
|
||||
|
||||
if (isInstruct) {
|
||||
textResult = formatInstructModeChat(itemName, chatItem.mes, chatItem.is_user, isNarratorType, chatItem.force_avatar, name1, name2);
|
||||
textResult = formatInstructModeChat(itemName, chatItem.mes, chatItem.is_user, isNarratorType, chatItem.force_avatar, name1, name2, forceLastOutputSequence);
|
||||
}
|
||||
|
||||
textResult = replaceBiasMarkup(textResult);
|
||||
@ -3965,14 +3970,16 @@ export function isMultigenEnabled() {
|
||||
|
||||
export function activateSendButtons() {
|
||||
is_send_press = false;
|
||||
$("#send_but").css("display", "flex");
|
||||
$("#send_but").removeClass("displayNone");
|
||||
$("#mes_continue").removeClass("displayNone");
|
||||
$("#send_textarea").attr("disabled", false);
|
||||
$('.mes_buttons:last').show();
|
||||
hideStopButton();
|
||||
}
|
||||
|
||||
export function deactivateSendButtons() {
|
||||
$("#send_but").css("display", "none");
|
||||
$("#send_but").addClass("displayNone");
|
||||
$("#mes_continue").addClass("displayNone");
|
||||
showStopButton();
|
||||
}
|
||||
|
||||
@ -4139,6 +4146,32 @@ async function renamePastChats(newAvatar, newValue) {
|
||||
}
|
||||
}
|
||||
|
||||
function saveChatDebounced() {
|
||||
const chid = this_chid;
|
||||
const selectedGroup = selected_group;
|
||||
|
||||
if (chatSaveTimeout) {
|
||||
console.debug('Clearing chat save timeout');
|
||||
clearTimeout(chatSaveTimeout);
|
||||
}
|
||||
|
||||
chatSaveTimeout = setTimeout(async () => {
|
||||
if (selectedGroup !== selected_group) {
|
||||
console.warn('Chat save timeout triggered, but group changed. Aborting.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (chid !== this_chid) {
|
||||
console.warn('Chat save timeout triggered, but chid changed. Aborting.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('Chat save timeout triggered');
|
||||
await saveChatConditional();
|
||||
console.debug('Chat saved');
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
async function saveChat(chat_name, withMetadata, mesId) {
|
||||
const metadata = { ...chat_metadata, ...(withMetadata || {}) };
|
||||
let file_name = chat_name ?? characters[this_chid].chat;
|
||||
@ -4290,7 +4323,6 @@ async function getChat() {
|
||||
chat_create_date = humanizedDateTime();
|
||||
}
|
||||
await getChatResult();
|
||||
saveChatDebounced();
|
||||
eventSource.emit('chatLoaded', { detail: { id: this_chid, character: characters[this_chid] } });
|
||||
|
||||
setTimeout(function () {
|
||||
@ -4306,26 +4338,9 @@ async function getChat() {
|
||||
async function getChatResult() {
|
||||
name2 = characters[this_chid].name;
|
||||
if (chat.length === 0) {
|
||||
const firstMes = characters[this_chid].first_mes || default_ch_mes;
|
||||
const alternateGreetings = characters[this_chid]?.data?.alternate_greetings;
|
||||
|
||||
chat[0] = {
|
||||
name: name2,
|
||||
is_user: false,
|
||||
is_name: true,
|
||||
send_date: getMessageTimeStamp(),
|
||||
mes: getRegexedString(firstMes, regex_placement.AI_OUTPUT),
|
||||
};
|
||||
|
||||
if (Array.isArray(alternateGreetings) && alternateGreetings.length > 0) {
|
||||
chat[0]['swipe_id'] = 0;
|
||||
chat[0]['swipes'] = [chat[0]['mes']].concat(
|
||||
alternateGreetings.map(
|
||||
(greeting) => substituteParams(getRegexedString(greeting, regex_placement.AI_OUTPUT))
|
||||
)
|
||||
);
|
||||
chat[0]['swipe_info'] = [];
|
||||
}
|
||||
const message = getFirstMessage();
|
||||
chat.push(message);
|
||||
await saveChatConditional();
|
||||
}
|
||||
printMessages();
|
||||
select_selected_character(this_chid);
|
||||
@ -4338,6 +4353,30 @@ async function getChatResult() {
|
||||
}
|
||||
}
|
||||
|
||||
function getFirstMessage() {
|
||||
const firstMes = characters[this_chid].first_mes || default_ch_mes;
|
||||
const alternateGreetings = characters[this_chid]?.data?.alternate_greetings;
|
||||
|
||||
const message = {
|
||||
name: name2,
|
||||
is_user: false,
|
||||
is_name: true,
|
||||
send_date: getMessageTimeStamp(),
|
||||
mes: getRegexedString(firstMes, regex_placement.AI_OUTPUT),
|
||||
};
|
||||
|
||||
if (Array.isArray(alternateGreetings) && alternateGreetings.length > 0) {
|
||||
message['swipe_id'] = 0;
|
||||
message['swipes'] = message['mes'].concat(
|
||||
alternateGreetings.map(
|
||||
(greeting) => substituteParams(getRegexedString(greeting, regex_placement.AI_OUTPUT))
|
||||
)
|
||||
);
|
||||
message['swipe_info'] = [];
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
async function openCharacterChat(file_name) {
|
||||
characters[this_chid]["chat"] = file_name;
|
||||
clearChat();
|
||||
@ -4872,7 +4911,7 @@ async function deleteUserAvatar() {
|
||||
if (avatarId === chat_metadata['persona']) {
|
||||
toastr.warning('The locked persona was deleted. You will need to set a new persona for this chat.', 'Persona deleted');
|
||||
delete chat_metadata['persona'];
|
||||
saveMetadata();
|
||||
await saveMetadata();
|
||||
}
|
||||
|
||||
saveSettingsDebounced();
|
||||
@ -4881,11 +4920,11 @@ async function deleteUserAvatar() {
|
||||
}
|
||||
}
|
||||
|
||||
function lockUserNameToChat() {
|
||||
async function lockUserNameToChat() {
|
||||
if (chat_metadata['persona']) {
|
||||
console.log(`Unlocking persona for this chat ${chat_metadata['persona']}`);
|
||||
delete chat_metadata['persona'];
|
||||
saveMetadata();
|
||||
await saveMetadata();
|
||||
if (power_user.persona_show_notifications) {
|
||||
toastr.info('User persona is now unlocked for this chat. Click the "Lock" again to revert.', 'Persona unlocked');
|
||||
}
|
||||
@ -4907,7 +4946,7 @@ function lockUserNameToChat() {
|
||||
}
|
||||
|
||||
chat_metadata['persona'] = user_avatar;
|
||||
saveMetadata();
|
||||
await saveMetadata();
|
||||
saveSettingsDebounced();
|
||||
console.log(`Locking persona for this chat ${user_avatar}`);
|
||||
if (power_user.persona_show_notifications) {
|
||||
@ -6006,23 +6045,38 @@ function hideSwipeButtons() {
|
||||
|
||||
async function saveMetadata() {
|
||||
if (selected_group) {
|
||||
await editGroup(selected_group, false, false);
|
||||
await editGroup(selected_group, true, false);
|
||||
}
|
||||
else {
|
||||
saveChatDebounced();
|
||||
await saveChatConditional();
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveChatConditional() {
|
||||
if (selected_group) {
|
||||
await saveGroupChat(selected_group, true);
|
||||
}
|
||||
else {
|
||||
await saveChat();
|
||||
try {
|
||||
await waitUntilCondition(() => !isChatSaving, durationSaveEdit, 100);
|
||||
} catch {
|
||||
console.warn('Timeout waiting for chat to save');
|
||||
return;
|
||||
}
|
||||
|
||||
// Save token cache to IndexedDB storage
|
||||
await saveTokenCache();
|
||||
try {
|
||||
isChatSaving = true;
|
||||
|
||||
if (selected_group) {
|
||||
await saveGroupChat(selected_group, true);
|
||||
}
|
||||
else {
|
||||
await saveChat();
|
||||
}
|
||||
|
||||
// Save token cache to IndexedDB storage
|
||||
saveTokenCache();
|
||||
} catch (error) {
|
||||
console.error('Error saving chat', error);
|
||||
} finally {
|
||||
isChatSaving = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function importCharacterChat(formData) {
|
||||
@ -6454,58 +6508,6 @@ async function createOrEditCharacter(e) {
|
||||
contentType: false,
|
||||
processData: false,
|
||||
success: async function (html) {
|
||||
if (chat.length === 1 && !selected_group) {
|
||||
var this_ch_mes = default_ch_mes;
|
||||
|
||||
if ($("#firstmessage_textarea").val() != "") {
|
||||
this_ch_mes = $("#firstmessage_textarea").val();
|
||||
}
|
||||
|
||||
if (
|
||||
this_ch_mes !=
|
||||
$.trim(
|
||||
$("#chat")
|
||||
.children(".mes")
|
||||
.children(".mes_block")
|
||||
.children(".mes_text")
|
||||
.text()
|
||||
)
|
||||
) {
|
||||
// MARK - kingbri: Regex on character greeting message
|
||||
// May need to be placed somewhere else
|
||||
this_ch_mes = getRegexedString(this_ch_mes, regex_placement.AI_OUTPUT);
|
||||
|
||||
clearChat();
|
||||
chat.length = 0;
|
||||
chat[0] = {};
|
||||
chat[0]["name"] = name2;
|
||||
chat[0]["is_user"] = false;
|
||||
chat[0]["is_name"] = true;
|
||||
chat[0]["mes"] = this_ch_mes;
|
||||
chat[0]["extra"] = {};
|
||||
chat[0]["send_date"] = getMessageTimeStamp();
|
||||
|
||||
const alternateGreetings = characters[this_chid]?.data?.alternate_greetings;
|
||||
|
||||
if (Array.isArray(alternateGreetings) && alternateGreetings.length > 0) {
|
||||
chat[0]['swipe_id'] = 0;
|
||||
chat[0]['swipes'] = [];
|
||||
chat[0]['swipe_info'] = [];
|
||||
chat[0]['swipes'][0] = chat[0]['mes'];
|
||||
|
||||
for (let i = 0; i < alternateGreetings.length; i++) {
|
||||
const alternateGreeting = getRegexedString(alternateGreetings[i], regex_placement.AI_OUTPUT);
|
||||
chat[0]['swipes'].push(substituteParams(alternateGreeting));
|
||||
}
|
||||
}
|
||||
|
||||
add_mes_without_animation = true;
|
||||
//console.log('form create submission calling addOneMessage');
|
||||
await eventSource.emit(event_types.MESSAGE_RECEIVED, (chat.length - 1));
|
||||
addOneMessage(chat[0]);
|
||||
await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, (chat.length - 1));
|
||||
}
|
||||
}
|
||||
$("#create_button").removeAttr("disabled");
|
||||
|
||||
await getOneCharacter(formData.get('avatar_url'));
|
||||
@ -6516,6 +6518,17 @@ async function createOrEditCharacter(e) {
|
||||
$("#create_button").attr("value", "Save");
|
||||
crop_data = undefined;
|
||||
eventSource.emit(event_types.CHARACTER_EDITED, { detail: { id: this_chid, character: characters[this_chid] } });
|
||||
|
||||
if (chat.length === 1 && !selected_group) {
|
||||
const firstMessage = getFirstMessage();
|
||||
chat[0] = firstMessage;
|
||||
|
||||
await eventSource.emit(event_types.MESSAGE_RECEIVED, (chat.length - 1));
|
||||
clearChat();
|
||||
printMessages();
|
||||
await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, (chat.length - 1));
|
||||
await saveChatConditional();
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, exception) {
|
||||
$("#create_button").removeAttr("disabled");
|
||||
@ -7153,7 +7166,7 @@ $(document).ready(function () {
|
||||
S_TAPreviouslyFocused = true;
|
||||
});
|
||||
$('#send_textarea').on('focusout blur', () => S_TAFocused = false);
|
||||
$('#options_button, #send_but, #option_regenerate').on('click', () => {
|
||||
$('#options_button, #send_but, #option_regenerate, #option_continue, #mes_continue').on('click', () => {
|
||||
if (S_TAPreviouslyFocused) {
|
||||
$('#send_textarea').focus();
|
||||
S_TAFocused = true;
|
||||
@ -7161,8 +7174,8 @@ $(document).ready(function () {
|
||||
});
|
||||
$(document).click(event => {
|
||||
if ($(':focus').attr('id') !== 'send_textarea') {
|
||||
var validIDs = ["options_button", "send_but", "send_textarea", "option_regenerate"];
|
||||
if ($(event.target).attr('id') !== validIDs) {
|
||||
var validIDs = ["options_button", "send_but", "mes_continue", "send_textarea", "option_regenerate", "option_continue"];
|
||||
if (!validIDs.includes($(event.target).attr('id'))) {
|
||||
S_TAFocused = false;
|
||||
S_TAPreviouslyFocused = false;
|
||||
}
|
||||
@ -7196,7 +7209,11 @@ $(document).ready(function () {
|
||||
entitiesFilter.setFilterData(FILTER_TYPES.SEARCH, searchValue);
|
||||
});
|
||||
|
||||
$("#send_but").click(function () {
|
||||
$("#mes_continue").on('click', function () {
|
||||
$("#option_continue").trigger('click');
|
||||
});
|
||||
|
||||
$("#send_but").on('click', function () {
|
||||
if (is_send_press == false) {
|
||||
is_send_press = true;
|
||||
Generate();
|
||||
@ -7471,14 +7488,15 @@ $(document).ready(function () {
|
||||
chat.length = 0;
|
||||
|
||||
if (selected_group) {
|
||||
createNewGroupChat(selected_group);
|
||||
await createNewGroupChat(selected_group);
|
||||
}
|
||||
else {
|
||||
//RossAscends: added character name to new chat filenames and replaced Date.now() with humanizedDateTime;
|
||||
chat_metadata = {};
|
||||
characters[this_chid].chat = name2 + " - " + humanizedDateTime();
|
||||
$("#selected_chat_pole").val(characters[this_chid].chat);
|
||||
getChat();
|
||||
await getChat();
|
||||
await createOrEditCharacter();
|
||||
}
|
||||
}
|
||||
|
||||
@ -7630,11 +7648,11 @@ $(document).ready(function () {
|
||||
else {
|
||||
if (characters[this_chid].chat == old_filename) {
|
||||
characters[this_chid].chat = newName;
|
||||
saveCharacterDebounced();
|
||||
await createOrEditCharacter();
|
||||
}
|
||||
}
|
||||
|
||||
reloadCurrentChat();
|
||||
await reloadCurrentChat();
|
||||
|
||||
await delay(250);
|
||||
$("#option_select_chat").trigger('click');
|
||||
@ -8008,6 +8026,32 @@ $(document).ready(function () {
|
||||
|
||||
////////////////// OPTIMIZED RANGE SLIDER LISTENERS////////////////
|
||||
|
||||
var sliderLocked = true;
|
||||
var sliderTimer;
|
||||
|
||||
$("input[type='range']").on("touchstart", function () {
|
||||
// Unlock the slider after 500ms
|
||||
sliderTimer = setTimeout(function () {
|
||||
sliderLocked = false;
|
||||
}, 500);
|
||||
});
|
||||
|
||||
$("input[type='range']").on("touchend", function () {
|
||||
clearTimeout(sliderTimer);
|
||||
$(this).css('background-color', '')
|
||||
sliderLocked = true
|
||||
});
|
||||
|
||||
$("input[type='range']").on("touchmove", function (event) {
|
||||
if (sliderLocked) {
|
||||
event.preventDefault();
|
||||
}
|
||||
else {
|
||||
$(this).css('background-color', 'var(--SmartThemeQuoteColor)')
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const sliders = [
|
||||
{
|
||||
sliderId: "#amount_gen",
|
||||
|
@ -1772,6 +1772,12 @@ const chatCompletionDefaultPrompts = {
|
||||
"system_prompt": true,
|
||||
"marker": true,
|
||||
},
|
||||
{
|
||||
"identifier": "personaDescription",
|
||||
"name": "Persona Description",
|
||||
"system_prompt": true,
|
||||
"marker": true,
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
@ -1788,6 +1794,10 @@ const promptManagerDefaultPromptOrder = [
|
||||
"identifier": "worldInfoBefore",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"identifier": "personaDescription",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"identifier": "charDescription",
|
||||
"enabled": true
|
||||
|
@ -315,7 +315,8 @@ function RA_checkOnlineStatus() {
|
||||
if (online_status == "no_connection") {
|
||||
$("#send_textarea").attr("placeholder", "Not connected to API!"); //Input bar placeholder tells users they are not connected
|
||||
$("#send_form").addClass('no-connection'); //entire input form area is red when not connected
|
||||
$("#send_but").css("display", "none"); //send button is hidden when not connected;
|
||||
$("#send_but").addClass("displayNone"); //send button is hidden when not connected;
|
||||
$("#mes_continue").addClass("displayNone"); //continue button is hidden when not connected;
|
||||
$("#API-status-top").removeClass("fa-plug");
|
||||
$("#API-status-top").addClass("fa-plug-circle-exclamation redOverlayGlow");
|
||||
connection_made = false;
|
||||
@ -330,7 +331,8 @@ function RA_checkOnlineStatus() {
|
||||
RA_AC_retries = 1;
|
||||
|
||||
if (!is_send_press && !(selected_group && is_group_generating)) {
|
||||
$("#send_but").css("display", "flex"); //on connect, send button shows
|
||||
$("#send_but").removeClass("displayNone"); //on connect, send button shows
|
||||
$("#mes_continue").removeClass("displayNone"); //continue button is shown when connected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,37 @@ export {
|
||||
let extensionNames = [];
|
||||
let manifests = {};
|
||||
const defaultUrl = "http://localhost:5100";
|
||||
export const saveMetadataDebounced = debounce(async () => await getContext().saveMetadata(), 1000);
|
||||
|
||||
let saveMetadataTimeout = null;
|
||||
|
||||
export function saveMetadataDebounced() {
|
||||
const context = getContext();
|
||||
const groupId = context.groupId;
|
||||
const characterId = context.characterId;
|
||||
|
||||
if (saveMetadataTimeout) {
|
||||
console.debug('Clearing save metadata timeout');
|
||||
clearTimeout(saveMetadataTimeout);
|
||||
}
|
||||
|
||||
saveMetadataTimeout = setTimeout(async () => {
|
||||
const newContext = getContext();
|
||||
|
||||
if (groupId !== newContext.groupId) {
|
||||
console.warn('Group changed, not saving metadata');
|
||||
return;
|
||||
}
|
||||
|
||||
if (characterId !== newContext.characterId) {
|
||||
console.warn('Character changed, not saving metadata');
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('Saving metadata...');
|
||||
newContext.saveMetadata();
|
||||
console.debug('Saved metadata...');
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
export const extensionsHandlebars = Handlebars.create();
|
||||
|
||||
|
@ -164,7 +164,7 @@ function getNextIncompleteTaskRecurse(task){
|
||||
}
|
||||
|
||||
// Set a task in extensionPrompt context. Defaults to first incomplete
|
||||
function setCurrentTask(taskId = null) {
|
||||
function setCurrentTask(taskId = null, skipSave = false) {
|
||||
const context = getContext();
|
||||
|
||||
// TODO: Should probably null this rather than set empty object
|
||||
@ -202,7 +202,10 @@ function setCurrentTask(taskId = null) {
|
||||
console.info(`No current task`);
|
||||
}
|
||||
|
||||
saveState();
|
||||
// Save state if not skipping
|
||||
if (!skipSave) {
|
||||
saveState();
|
||||
}
|
||||
}
|
||||
|
||||
function getHighestTaskIdRecurse(task) {
|
||||
@ -731,7 +734,7 @@ function loadSettings() {
|
||||
$('#objective-check-frequency').val(chat_metadata['objective'].checkFrequency)
|
||||
$('#objective-hide-tasks').prop('checked', chat_metadata['objective'].hideTasks)
|
||||
$('#objective-tasks').prop('hidden', $('#objective-hide-tasks').prop('checked'))
|
||||
setCurrentTask()
|
||||
setCurrentTask(null, true)
|
||||
}
|
||||
|
||||
function addManualTaskCheckUi() {
|
||||
|
@ -818,7 +818,7 @@ function addSDGenButtons() {
|
||||
$(document).on('click touchend', function (e) {
|
||||
const target = $(e.target);
|
||||
if (target.is(dropdown)) return;
|
||||
if (target.is(button) && !dropdown.is(":visible") && $("#send_but").css('display') === 'flex') {
|
||||
if (target.is(button) && !dropdown.is(":visible") && $("#send_but").is(":visible")) {
|
||||
e.preventDefault();
|
||||
|
||||
dropdown.fadeIn(250);
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { deepClone } from "../../utils.js";
|
||||
|
||||
export { ElevenLabsTtsProvider }
|
||||
|
||||
class ElevenLabsTtsProvider {
|
||||
@ -47,18 +49,20 @@ class ElevenLabsTtsProvider {
|
||||
|
||||
loadSettings(settings) {
|
||||
// Pupulate Provider UI given input settings
|
||||
if (Object.keys(settings).length == 0) {
|
||||
if (!settings || Object.keys(settings).length == 0) {
|
||||
console.info("Using default TTS Provider settings")
|
||||
}
|
||||
|
||||
// Only accept keys defined in defaultSettings
|
||||
this.settings = this.defaultSettings
|
||||
this.settings = deepClone(this.defaultSettings);
|
||||
|
||||
for (const key in settings){
|
||||
if (key in this.settings){
|
||||
this.settings[key] = settings[key]
|
||||
} else {
|
||||
throw `Invalid setting passed to TTS Provider: ${key}`
|
||||
if (settings) {
|
||||
for (const key in settings) {
|
||||
if (key in this.settings) {
|
||||
this.settings[key] = settings[key]
|
||||
} else {
|
||||
throw `Invalid setting passed to TTS Provider: ${key}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,7 @@ import {
|
||||
setScenarioOverride,
|
||||
getCropPopup,
|
||||
system_avatar,
|
||||
isChatSaving,
|
||||
} from "../script.js";
|
||||
import { appendTagToList, createTagMapFromList, getTagsList, applyTagsOnCharacterSelect, tag_map, printTagFilters } from './tags.js';
|
||||
import { FILTER_TYPES, FilterHelper } from './filters.js';
|
||||
@ -1272,6 +1273,11 @@ function updateFavButtonState(state) {
|
||||
}
|
||||
|
||||
export async function openGroupById(groupId) {
|
||||
if (isChatSaving) {
|
||||
toastr.info("Please wait until the chat is saved before switching characters.", "Your chat is still saving...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!groups.find(x => x.id === groupId)) {
|
||||
console.log('Group not found', groupId);
|
||||
return;
|
||||
|
@ -2,7 +2,10 @@
|
||||
|
||||
import { saveSettingsDebounced, substituteParams } from "../script.js";
|
||||
import { selected_group } from "./group-chats.js";
|
||||
import { power_user } from "./power-user.js";
|
||||
import {
|
||||
power_user,
|
||||
context_presets,
|
||||
} from "./power-user.js";
|
||||
|
||||
/**
|
||||
* @type {any[]} Instruct mode presets.
|
||||
@ -69,6 +72,48 @@ function highlightDefaultPreset() {
|
||||
$('#instruct_set_default').toggleClass('default', power_user.default_instruct === power_user.instruct.preset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select context template if not already selected.
|
||||
* @param {string} preset Preset name.
|
||||
*/
|
||||
function selectContextPreset(preset) {
|
||||
// If context template is not already selected, select it
|
||||
if (preset !== power_user.context.preset) {
|
||||
$('#context_presets').val(preset).trigger('change');
|
||||
toastr.info(`Context Template: preset "${preset}" auto-selected`);
|
||||
}
|
||||
|
||||
// If instruct mode is disabled, enable it, except for default context template
|
||||
if (!power_user.instruct.enabled && preset !== 'Default') {
|
||||
power_user.instruct.enabled = true;
|
||||
$('#instruct_enabled').prop('checked', true).trigger('change');
|
||||
toastr.info(`Instruct Mode enabled`);
|
||||
}
|
||||
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
/**
|
||||
* Select instruct preset if not already selected.
|
||||
* @param {string} preset Preset name.
|
||||
*/
|
||||
export function selectInstructPreset(preset) {
|
||||
// If instruct preset is not already selected, select it
|
||||
if (preset !== power_user.instruct.preset) {
|
||||
$('#instruct_presets').val(preset).trigger('change');
|
||||
toastr.info(`Instruct Mode: preset "${preset}" auto-selected`);
|
||||
}
|
||||
|
||||
// If instruct mode is disabled, enable it
|
||||
if (!power_user.instruct.enabled) {
|
||||
power_user.instruct.enabled = true;
|
||||
$('#instruct_enabled').prop('checked', true).trigger('change');
|
||||
toastr.info(`Instruct Mode enabled`);
|
||||
}
|
||||
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically select instruct preset based on model id.
|
||||
* Otherwise, if default instruct preset is set, selects it.
|
||||
@ -81,33 +126,42 @@ export function autoSelectInstructPreset(modelId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const preset of instruct_presets) {
|
||||
// If activation regex is set, check if it matches the model id
|
||||
if (preset.activation_regex) {
|
||||
try {
|
||||
const regex = new RegExp(preset.activation_regex, 'i');
|
||||
// Select matching instruct preset
|
||||
let foundMatch = false;
|
||||
for (const instruct_preset of instruct_presets) {
|
||||
// If instruct preset matches the context template
|
||||
if (instruct_preset.name === power_user.context.preset) {
|
||||
foundMatch = true;
|
||||
selectInstructPreset(instruct_preset.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If no match was found, auto-select instruct preset
|
||||
if (!foundMatch) {
|
||||
for (const preset of instruct_presets) {
|
||||
// If activation regex is set, check if it matches the model id
|
||||
if (preset.activation_regex) {
|
||||
try {
|
||||
const regex = new RegExp(preset.activation_regex, 'i');
|
||||
|
||||
// Stop on first match so it won't cycle back and forth between presets if multiple regexes match
|
||||
if (regex.test(modelId)) {
|
||||
// If preset is not already selected, select it
|
||||
if (power_user.instruct.preset !== preset.name) {
|
||||
$('#instruct_presets').val(preset.name).trigger('change');
|
||||
toastr.info(`Instruct mode: preset "${preset.name}" auto-selected`);
|
||||
// Stop on first match so it won't cycle back and forth between presets if multiple regexes match
|
||||
if (regex.test(modelId)) {
|
||||
selectInstructPreset(preset.name);
|
||||
|
||||
return true;
|
||||
}
|
||||
} catch {
|
||||
// If regex is invalid, ignore it
|
||||
console.warn(`Invalid instruct activation regex in preset "${preset.name}"`);
|
||||
}
|
||||
} catch {
|
||||
// If regex is invalid, ignore it
|
||||
console.warn(`Invalid instruct activation regex in preset "${preset.name}"`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (power_user.default_instruct && power_user.instruct.preset !== power_user.default_instruct) {
|
||||
if (instruct_presets.some(p => p.name === power_user.default_instruct)) {
|
||||
console.log(`Instruct mode: default preset "${power_user.default_instruct}" selected`);
|
||||
$('#instruct_presets').val(power_user.default_instruct).trigger('change');
|
||||
if (power_user.default_instruct && power_user.instruct.preset !== power_user.default_instruct) {
|
||||
if (instruct_presets.some(p => p.name === power_user.default_instruct)) {
|
||||
console.log(`Instruct mode: default preset "${power_user.default_instruct}" selected`);
|
||||
$('#instruct_presets').val(power_user.default_instruct).trigger('change');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,9 +219,10 @@ export function getInstructStoppingSequences() {
|
||||
* @param {string} forceAvatar Force avatar string.
|
||||
* @param {string} name1 User name.
|
||||
* @param {string} name2 Character name.
|
||||
* @param {boolean} forceLastOutputSequence Force to use last outline sequence (if configured).
|
||||
* @returns {string} Formatted instruct mode chat message.
|
||||
*/
|
||||
export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvatar, name1, name2) {
|
||||
export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvatar, name1, name2, forceLastOutputSequence) {
|
||||
let includeNames = isNarrator ? false : power_user.instruct.names;
|
||||
|
||||
if (!isNarrator && power_user.instruct.names_force_groups && (selected_group || forceAvatar)) {
|
||||
@ -176,6 +231,10 @@ export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvata
|
||||
|
||||
let sequence = (isUser || isNarrator) ? power_user.instruct.input_sequence : power_user.instruct.output_sequence;
|
||||
|
||||
if (sequence === power_user.instruct.output_sequence && forceLastOutputSequence && power_user.instruct.last_output_sequence) {
|
||||
sequence = power_user.instruct.last_output_sequence;
|
||||
}
|
||||
|
||||
if (power_user.instruct.macro) {
|
||||
sequence = substituteParams(sequence, name1, name2);
|
||||
}
|
||||
@ -273,6 +332,16 @@ jQuery(() => {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#instruct_enabled').on('change', function () {
|
||||
// When instruct mode gets enabled, select context template matching selected instruct preset
|
||||
if (power_user.instruct.enabled) {
|
||||
$('#instruct_presets').trigger('change');
|
||||
// When instruct mode gets disabled, select default context preset
|
||||
} else {
|
||||
selectContextPreset('Default');
|
||||
}
|
||||
});
|
||||
|
||||
$('#instruct_presets').on('change', function () {
|
||||
const name = $(this).find(':selected').val();
|
||||
const preset = instruct_presets.find(x => x.name === name);
|
||||
@ -295,6 +364,21 @@ jQuery(() => {
|
||||
}
|
||||
});
|
||||
|
||||
// Select matching context template
|
||||
let foundMatch = false;
|
||||
for (const context_preset of context_presets) {
|
||||
// If context template matches the instruct preset
|
||||
if (context_preset.name === name) {
|
||||
foundMatch = true;
|
||||
selectContextPreset(context_preset.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundMatch) {
|
||||
// If no match was found, select default context preset
|
||||
selectContextPreset('Default');
|
||||
}
|
||||
|
||||
highlightDefaultPreset();
|
||||
});
|
||||
});
|
||||
|
@ -339,7 +339,7 @@ function setupChatCompletionPromptManager(openAiSettings) {
|
||||
},
|
||||
promptOrder: {
|
||||
strategy: 'global',
|
||||
dummyId: 100000
|
||||
dummyId: 100001
|
||||
},
|
||||
};
|
||||
|
||||
@ -577,6 +577,7 @@ function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, ty
|
||||
addToChatCompletion('charDescription');
|
||||
addToChatCompletion('charPersonality');
|
||||
addToChatCompletion('scenario');
|
||||
addToChatCompletion('personaDescription')
|
||||
|
||||
// Collection of control prompts that will always be positioned last
|
||||
const controlPrompts = new MessageCollection('controlPrompts');
|
||||
@ -626,34 +627,6 @@ function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, ty
|
||||
if (true === afterScenario) chatCompletion.insert(authorsNote, 'scenario');
|
||||
}
|
||||
|
||||
// Persona Description
|
||||
if (power_user.persona_description) {
|
||||
const personaDescription = Message.fromPrompt(prompts.get('personaDescription'));
|
||||
|
||||
try {
|
||||
switch (power_user.persona_description_position) {
|
||||
case persona_description_positions.BEFORE_CHAR:
|
||||
chatCompletion.insertAtStart(personaDescription, 'charDescription');
|
||||
break;
|
||||
case persona_description_positions.AFTER_CHAR:
|
||||
chatCompletion.insertAtEnd(personaDescription, 'charDescription');
|
||||
break;
|
||||
case persona_description_positions.TOP_AN:
|
||||
chatCompletion.insertAtStart(personaDescription, 'authorsNote');
|
||||
break;
|
||||
case persona_description_positions.BOTTOM_AN:
|
||||
chatCompletion.insertAtEnd(personaDescription, 'authorsNote');
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof IdentifierNotFoundError) {
|
||||
// Error is acceptable in this context
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decide whether dialogue examples should always be added
|
||||
if (power_user.pin_examples) {
|
||||
populateDialogueExamples(prompts, chatCompletion);
|
||||
@ -679,10 +652,12 @@ function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, ty
|
||||
* @param {string} quietPrompt - The quiet prompt to be used in the conversation.
|
||||
* @param {string} bias - The bias to be added in the conversation.
|
||||
* @param {Object} extensionPrompts - An object containing additional prompts.
|
||||
*
|
||||
* @param {string} systemPromptOverride
|
||||
* @param {string} jailbreakPromptOverride
|
||||
* @param {string} personaDescription
|
||||
* @returns {Object} prompts - The prepared and merged system and user-defined prompts.
|
||||
*/
|
||||
function preparePromptsForChatCompletion(Scenario, charPersonality, name2, worldInfoBefore, worldInfoAfter, charDescription, quietPrompt, bias, extensionPrompts, systemPromptOverride, jailbreakPromptOverride) {
|
||||
function preparePromptsForChatCompletion({Scenario, charPersonality, name2, worldInfoBefore, worldInfoAfter, charDescription, quietPrompt, bias, extensionPrompts, systemPromptOverride, jailbreakPromptOverride, personaDescription} = {}) {
|
||||
const scenarioText = Scenario ? `[Circumstances and context of the dialogue: ${Scenario}]` : '';
|
||||
const charPersonalityText = charPersonality ? `[${name2}'s personality: ${charPersonality}]` : ''
|
||||
const groupNudge = `[Write the next reply only as ${name2}]`;
|
||||
@ -695,6 +670,7 @@ function preparePromptsForChatCompletion(Scenario, charPersonality, name2, world
|
||||
{ role: 'system', content: charDescription, identifier: 'charDescription' },
|
||||
{ role: 'system', content: charPersonalityText, identifier: 'charPersonality' },
|
||||
{ role: 'system', content: scenarioText, identifier: 'scenario' },
|
||||
{ role: 'system', content: personaDescription, identifier: 'personaDescription' },
|
||||
// Unordered prompts without marker
|
||||
{ role: 'system', content: oai_settings.nsfw_avoidance_prompt, identifier: 'nsfwAvoidance' },
|
||||
{ role: 'system', content: oai_settings.impersonation_prompt, identifier: 'impersonate' },
|
||||
@ -793,6 +769,7 @@ function prepareOpenAIMessages({
|
||||
cyclePrompt,
|
||||
systemPromptOverride,
|
||||
jailbreakPromptOverride,
|
||||
personaDescription
|
||||
} = {}, dryRun) {
|
||||
// Without a character selected, there is no way to accurately calculate tokens
|
||||
if (!promptManager.activeCharacter && dryRun) return [null, false];
|
||||
@ -805,7 +782,19 @@ function prepareOpenAIMessages({
|
||||
|
||||
try {
|
||||
// Merge markers and ordered user prompts with system prompts
|
||||
const prompts = preparePromptsForChatCompletion(Scenario, charPersonality, name2, worldInfoBefore, worldInfoAfter, charDescription, quietPrompt, bias, extensionPrompts, systemPromptOverride, jailbreakPromptOverride);
|
||||
const prompts = preparePromptsForChatCompletion({
|
||||
Scenario,
|
||||
charPersonality,
|
||||
name2,
|
||||
worldInfoBefore,
|
||||
worldInfoAfter,
|
||||
charDescription,
|
||||
quietPrompt,
|
||||
bias,
|
||||
extensionPrompts,
|
||||
systemPromptOverride,
|
||||
jailbreakPromptOverride,
|
||||
personaDescription});
|
||||
|
||||
// Fill the chat completion with as much context as the budget allows
|
||||
populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, type, cyclePrompt });
|
||||
@ -2548,7 +2537,7 @@ function getMaxContextWindowAI(value) {
|
||||
|
||||
async function onModelChange() {
|
||||
biasCache = undefined;
|
||||
let value = String($(this).val());
|
||||
let value = String($(this).val() || '');
|
||||
|
||||
if ($(this).is('#model_claude_select')) {
|
||||
console.log('Claude model changed to', value);
|
||||
|
@ -20,7 +20,11 @@ import {
|
||||
groups,
|
||||
resetSelectedGroup,
|
||||
} from "./group-chats.js";
|
||||
import { loadInstructMode } from "./instruct-mode.js";
|
||||
import {
|
||||
instruct_presets,
|
||||
loadInstructMode,
|
||||
selectInstructPreset,
|
||||
} from "./instruct-mode.js";
|
||||
|
||||
import { registerSlashCommand } from "./slash-commands.js";
|
||||
import { tokenizers } from "./tokenizers.js";
|
||||
@ -147,7 +151,7 @@ let power_user = {
|
||||
max_context_unlocked: false,
|
||||
prefer_character_prompt: true,
|
||||
prefer_character_jailbreak: true,
|
||||
continue_on_send: false,
|
||||
quick_continue: false,
|
||||
trim_spaces: true,
|
||||
relaxed_api_urls: false,
|
||||
|
||||
@ -193,7 +197,7 @@ let power_user = {
|
||||
|
||||
let themes = [];
|
||||
let movingUIPresets = [];
|
||||
let context_presets = [];
|
||||
export let context_presets = [];
|
||||
|
||||
const storage_keys = {
|
||||
fast_ui_mode: "TavernAI_fast_ui_mode",
|
||||
@ -704,7 +708,8 @@ function loadPowerUserSettings(settings, data) {
|
||||
|
||||
$('#relaxed_api_urls').prop("checked", power_user.relaxed_api_urls);
|
||||
$('#trim_spaces').prop("checked", power_user.trim_spaces);
|
||||
$('#continue_on_send').prop("checked", power_user.continue_on_send);
|
||||
$('#quick_continue').prop("checked", power_user.quick_continue);
|
||||
$('#mes_continue').css('display', power_user.quick_continue ? '' : 'none');
|
||||
$('#auto_swipe').prop("checked", power_user.auto_swipe);
|
||||
$('#auto_swipe_minimum_length').val(power_user.auto_swipe_minimum_length);
|
||||
$('#auto_swipe_blacklist').val(power_user.auto_swipe_blacklist.join(", "));
|
||||
@ -920,6 +925,15 @@ function loadContextSettings() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Select matching instruct preset
|
||||
for (const instruct_preset of instruct_presets) {
|
||||
// If instruct preset matches the context template
|
||||
if (instruct_preset.name === name) {
|
||||
selectInstructPreset(instruct_preset.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1954,9 +1968,10 @@ $(document).ready(() => {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$("#continue_on_send").on("input", function () {
|
||||
$("#quick_continue").on("input", function () {
|
||||
const value = !!$(this).prop('checked');
|
||||
power_user.continue_on_send = value;
|
||||
power_user.quick_continue = value;
|
||||
$("#mes_continue").css('display', value ? '' : 'none');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
|
@ -1156,8 +1156,8 @@ async function checkWorldInfo(chat, maxContext) {
|
||||
}
|
||||
});
|
||||
|
||||
const worldInfoBefore = WIBeforeEntries.length ? `${WIBeforeEntries.join("\n")}\n` : '';
|
||||
const worldInfoAfter = WIAfterEntries.length ? `${WIAfterEntries.join("\n")}\n` : '';
|
||||
const worldInfoBefore = WIBeforeEntries.length ? WIBeforeEntries.join("\n") : '';
|
||||
const worldInfoAfter = WIAfterEntries.length ? WIAfterEntries.join("\n") : '';
|
||||
|
||||
if (shouldWIAddPrompt) {
|
||||
const originalAN = context.extensionPrompts[NOTE_MODULE_NAME].value;
|
||||
|
@ -543,13 +543,16 @@ hr {
|
||||
}
|
||||
|
||||
#send_but {
|
||||
display: none;
|
||||
order: 99999;
|
||||
}
|
||||
|
||||
#mes_continue {
|
||||
order: 99998;
|
||||
}
|
||||
|
||||
.mes_stop {
|
||||
display: none;
|
||||
order: 99998;
|
||||
order: 99997;
|
||||
}
|
||||
|
||||
#options_button {
|
||||
|
Loading…
x
Reference in New Issue
Block a user