Merge branch 'SillyTavern:staging' into staging

This commit is contained in:
Tony Ribeiro 2023-08-21 05:36:47 +02:00 committed by GitHub
commit 173cb6358b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 680 additions and 360 deletions

1
.gitignore vendored
View File

@ -13,6 +13,7 @@ public/OpenAI Settings/
public/KoboldAI Settings/
public/NovelAI Settings/
public/TextGen Settings/
public/instruct/
public/scripts/extensions/third-party/
public/stats.json
/uploads/

View File

@ -133,7 +133,7 @@
"output_sequence": "### Response:",
"preset": "Alpaca",
"separator_sequence": "",
"macro": false
"macro": true
},
"personas": {},
"default_persona": null,

View File

@ -1,6 +1,6 @@
{
"name": "Default",
"story_string": "{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}{{/if}}",
"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}}",
"chat_start": "***",
"example_separator": "***"
}

View File

@ -1,6 +1,6 @@
{
"name": "Pygmalion",
"story_string": "{{#if description}}{{{char}}}'s Persona: {{description}}{{/if}}\n{{#if personality}}Personality: {{personality}}{{/if}}\n{{#if scenario}}Scenario: {{scenario}}{{/if}}",
"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}}",
"chat_start": "<START>",
"example_separator": "<START>"
}

View File

@ -1,6 +1,6 @@
{
"name": "Roleplay",
"story_string": "### Input:\n{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}{{/if}}",
"story_string": "{{#if system}}{{system}}\n{{/if}}### Input:\n{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}",
"chat_start": "### New Roleplay:",
"example_separator": "### New Roleplay:"
}

View File

@ -1,6 +1,6 @@
{
"name": "simple-proxy-for-tavern",
"story_string": "### Input:\n{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\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 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)",
"chat_start": "### New Roleplay:",
"example_separator": "### New Roleplay:"
}

View File

@ -363,8 +363,8 @@
"Not Connected": "未连接",
"Persona Management": "用户角色设置",
"Persona Description": "用户角色描述",
"Before Character Card": "角色卡之前",
"After Character Card": "角色卡之后",
"In Story String / Chat Completion: Before Character Card": "在故事串中 / Chat Completion: 角色卡之前",
"In Story String / Chat Completion: After Character Card": "在故事串中 / Chat Completion: 角色卡之后",
"Top of Author's Note": "作者注释之前",
"Bottom of Author's Note": "作者注释之后",
"How do I use this?": "用户角色设置说明",
@ -915,8 +915,8 @@
"Not Connected": "NEEDS TRANSLATION",
"Persona Management": "NEEDS TRANSLATION",
"Persona Description": "NEEDS TRANSLATION",
"Before Character Card": "NEEDS TRANSLATION",
"After Character Card": "NEEDS TRANSLATION",
"In Story String / Chat Completion: Before Character Card": "NEEDS TRANSLATION",
"In Story String / Chat Completion: After Character Card": "NEEDS TRANSLATION",
"Top of Author's Note": "NEEDS TRANSLATION",
"Bottom of Author's Note": "NEEDS TRANSLATION",
"How do I use this?": "NEEDS TRANSLATION",
@ -1472,8 +1472,8 @@
"Not Connected": "접속되지 않음",
"Persona Management": "주인공 관리",
"Persona Description": "주인공 묘사",
"Before Character Card": "캐릭터 카드 앞에",
"After Character Card": "캐릭터 카드 다음에",
"In Story String / Chat Completion: Before Character Card": "스토리 문자열에서 / 문장완성: 캐릭터 카드 앞에",
"In Story String / Chat Completion: After Character Card": "스토리 문자열에서 / 문장완성: 캐릭터 카드 다음에",
"Top of Author's Note": "글쓴이 쪽지 위에",
"Bottom of Author's Note": "글쓴이 쪽지 밑에",
"How do I use this?": "이건 어떻게 써먹나요?",
@ -2029,8 +2029,8 @@
"Not Connected": "Не подключено",
"Persona Management": "Управление Персоной",
"Persona Description": "Описание Персоны",
"Before Character Card": "Перед Карточкой Персонажа",
"After Character Card": "После Карточки Персонажа",
"In Story String / Chat Completion: Before Character Card": "В строке истории / Дополнение диалога: Перед Карточкой Персонажа",
"In Story String / Chat Completion: After Character Card": "В строке истории / Дополнение диалога: После Карточки Персонажа",
"Top of Author's Note": "Перед Авторскими Заметками",
"Bottom of Author's Note": "После Авторских Заметок",
"How do I use this?": "Как мне это использовать?",

View File

@ -149,7 +149,6 @@
<div class="scrollableInner">
<div class="flex-container" id="ai_response_configuration">
<div id="respective-presets-block" class="width100p">
<input type="file" hidden data-preset-manager-file="" accept=".json, .settings">
<div id="kobold_api-presets">
<h3><span data-i18n="kobldpresets">Kobold Presets</span>
<a href="https://docs.sillytavern.app/usage/api-connections/koboldai/" class="notes-link" target="_blank">
@ -161,6 +160,7 @@
<select id="settings_perset" data-preset-manager-for="kobold">
<option value="gui" data-i18n="guikoboldaisettings">GUI KoboldAI Settings</option>
</select>
<input type="file" hidden data-preset-manager-file="kobold" accept=".json, .settings">
<i data-preset-manager-update="kobold" class="menu_button fa-solid fa-save" title="Update current preset" data-i18n="[title]Update current preset"></i>
<i data-preset-manager-new="kobold" class="menu_button fa-solid fa-plus" title="Create new preset" data-i18n="[title]Create new preset"></i>
<i data-preset-manager-import="kobold" class="menu_button fa-solid fa-file-import" title="Import preset" data-i18n="[title]Import preset"></i>
@ -179,6 +179,7 @@
<select id="settings_perset_novel" data-preset-manager-for="novel">
<option value="gui" data-i18n="default">Default</option>
</select>
<input type="file" hidden data-preset-manager-file="novel" accept=".json, .settings">
<i data-preset-manager-update="novel" class="menu_button fa-solid fa-save" title="Update current preset" data-i18n="[title]Update current preset"></i>
<i data-preset-manager-new="novel" class="menu_button fa-solid fa-plus" title="Create new preset" data-i18n="[title]Create new preset"></i>
<i data-preset-manager-import="novel" class="menu_button fa-solid fa-file-import" title="Import preset" data-i18n="[title]Import preset"></i>
@ -208,6 +209,7 @@
<div class="preset_buttons">
<select id="settings_preset_textgenerationwebui" data-preset-manager-for="textgenerationwebui">
</select>
<input type="file" hidden data-preset-manager-file="textgenerationwebui" accept=".json, .settings">
<i data-preset-manager-update="textgenerationwebui" class="menu_button fa-solid fa-save" title="Update current preset" data-i18n="[title]Update current preset"></i>
<i data-preset-manager-new="textgenerationwebui" class="menu_button fa-solid fa-plus" title="Create new preset" data-i18n="[title]Create new preset"></i>
<i data-preset-manager-import="textgenerationwebui" class="menu_button fa-solid fa-file-import" title="Import preset" data-i18n="[title]Import preset"></i>
@ -1454,6 +1456,14 @@
<span data-i18n="Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.">Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.</span>
</div>
</div>
<div class="range-block" data-source="claude">
<label for="exclude_assistant" title="Exclude Assistant suffix" class="checkbox_label widthFreeExpand">
<input id="exclude_assistant" type="checkbox" /><span data-i18n="Exclude Assistant suffix">Exclude Assistant suffix</span>
</label>
<div class="toggle-description justifyLeft">
<span data-i18n="Exclude the assistant suffix from being added to the end of prompt.">Exclude the assistant suffix from being added to the end of prompt (Requires jailbreak with 'Assistant:' in it).</span>
</div>
</div>
<div class="inline-drawer m-t-1 wide100p">
<div class="inline-drawer-toggle inline-drawer-header">
<b data-i18n="Quick Edit">Quick Edit</b>
@ -1465,8 +1475,8 @@
<span data-i18n="Select a character to show quick edit options.">Select a character to show quick edit options.</span>
</div>
</div>
<div class="range-block" data-source="claude">
<span data-i18n="Assistant Prefill">Assistant Prefill</span>
<div id="claude_assistant_prefill_block" data-source="claude" class="range-block">
<span id="claude_assistant_prefill_text" data-i18n="Assistant Prefill">Assistant Prefill</span>
<textarea id="claude_assistant_prefill" class="text_pole textarea_compact" name="assistant_prefill" rows="3" maxlength="5000" placeholder="Start Claude's answer with..."></textarea>
</div>
</div>
@ -2133,12 +2143,15 @@
<label for="instruct_presets">
<span data-i18n="Presets">Presets</span>
</label>
<div class="flex-container">
<select id="instruct_presets" class="flex1 margin0"></select>
<div id="instruct_set_default" class="menu_button menu_button_icon margin0">
<i class="fa-solid fa-xs fa-fw fa-heart"></i>
<span data-i18n="Default">Default</span>
</div>
<div class="preset_buttons">
<select id="instruct_presets" data-preset-manager-for="instruct" class="flex1"></select>
<input type="file" hidden data-preset-manager-file="instruct" accept=".json, .settings">
<i id="instruct_set_default" class="menu_button fa-solid fa-heart" title="Auto-select this preset on API connection."></i>
<i data-preset-manager-update="instruct" class="menu_button fa-solid fa-save" title="Update current preset" data-i18n="[title]Update current preset"></i>
<i data-preset-manager-new="instruct" class="menu_button fa-solid fa-plus" title="Create new preset" data-i18n="[title]Create new preset"></i>
<i data-preset-manager-import="instruct" class="menu_button fa-solid fa-file-import" title="Import preset" data-i18n="[title]Import preset"></i>
<i data-preset-manager-export="instruct" class="menu_button fa-solid fa-file-export" title="Export preset" data-i18n="[title]Export preset"></i>
<i data-preset-manager-delete="instruct" class="menu_button fa-solid fa-trash-can" title="Delete the preset" data-i18n="[title]Delete the preset"></i>
</div>
<label>
<small data-i18n="Activation Regex">
@ -2257,6 +2270,10 @@
Keep Example Messages in Prompt
</span>
</label>
<label class="checkbox_label" for="remove-examples-checkbox">
<input id="remove-examples-checkbox" type="checkbox" />
Strip Example Messages from Prompt
</label>
<label class="checkbox_label" for="collapse-newlines-checkbox"><input id="collapse-newlines-checkbox" type="checkbox" />
<span data-i18n="Remove Empty New Lines from Output">
Remove Empty New Lines from Output
@ -2994,8 +3011,8 @@
<textarea id="persona_description" name="persona_description" placeholder="Example:&#10;[{{user}} is a 28-year-old Romanian cat girl.]" class="text_pole textarea_compact" maxlength="5000" value="" autocomplete="off" rows="4"></textarea>
<label for="persona_description_position" data-i18n="Position:">Position:</label>
<select id="persona_description_position">
<option value="0" data-i18n="Before Character Card">Before Character Card</option>
<option value="1" data-i18n="After Character Card">After Character Card</option>
<option value="0" data-i18n="In Story String / Chat Completion: Before Character Card">In Story String / Chat Completion: Before Character Card</option>
<option value="1" data-i18n="In Story String / Chat Completion: After Character Card">In Story String / Chat Completion: After Character Card</option>
<option value="2" data-i18n="Top of Author's Note">Top of Author's Note</option>
<option value="3" data-i18n="Bottom of Author's Note">Bottom of Author's Note</option>
</select>

View File

@ -1,11 +1,15 @@
{
"name": "Alpaca",
"system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\nWrite {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n",
"system_sequence": "",
"stop_sequence": "",
"input_sequence": "### Instruction:",
"output_sequence": "### Response:",
"last_output_sequence": "",
"system_sequence": "",
"stop_sequence": "",
"separator_sequence": "",
"wrap": true
"wrap": true,
"macro": true,
"names": false,
"names_force_groups": true,
"activation_regex": ""
}

View File

@ -1,11 +1,15 @@
{
"name": "Koala",
"system_prompt": "Write {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n",
"system_sequence": "BEGINNING OF CONVERSATION: ",
"stop_sequence": "",
"input_sequence": "USER: ",
"output_sequence": "GPT: ",
"last_output_sequence": "",
"system_sequence": "BEGINNING OF CONVERSATION: ",
"stop_sequence": "",
"separator_sequence": "</s>",
"wrap": false
"wrap": false,
"macro": true,
"names": false,
"names_force_groups": true,
"activation_regex": ""
}

View File

@ -1,11 +1,15 @@
{
"name": "Llama 2",
"system_prompt": "Write {{char}}'s next reply in this fictional roleplay with {{user}}.\n<</SYS>>\n",
"system_prompt": "[INST] <<SYS>>\nWrite {{char}}'s next reply in this fictional roleplay with {{user}}.\n<</SYS>>\n",
"input_sequence": "[INST] ",
"output_sequence": " [/INST] ",
"last_output_sequence": "",
"system_sequence": "[INST] <<SYS>>\n",
"stop_sequence": "",
"input_sequence": "[INST]",
"output_sequence": "[/INST]",
"last_output_sequence": "",
"separator_sequence": "\n",
"wrap": false
"wrap": false,
"macro": true,
"names": false,
"names_force_groups": true,
"activation_regex": ""
}

View File

@ -1,11 +1,15 @@
{
"name": "Metharme",
"system_prompt": "Enter roleplay mode. You must act as {{char}}, whose persona follows:",
"system_sequence": "<|system|>",
"stop_sequence": "</s>",
"input_sequence": "<|user|>",
"output_sequence": "<|model|>",
"last_output_sequence": "",
"system_sequence": "<|system|>",
"stop_sequence": "</s>",
"separator_sequence": "",
"wrap": false
"wrap": false,
"macro": true,
"names": false,
"names_force_groups": true,
"activation_regex": ""
}

View File

@ -1,13 +1,15 @@
{
"input_sequence": "User: ",
"macro": true,
"name": "OpenOrca/OpenChat",
"names": true,
"system_prompt": "You are a helpful assistant. Please answer truthfully and write out your thinking step by step to be sure you get the right answer. If you make a mistake or encounter an error in your thinking, say so out loud and attempt to correct it. If you don't know or aren't sure about something, say so clearly. You will act as a professional logician, mathematician, and physicist. You will also act as the most appropriate type of expert to answer any particular question or solve the relevant problem; state which expert type your are, if so. Also think of any particular named expert that would be ideal to answer the relevant question or solve the relevant problem; name and act as them, if appropriate.\n",
"input_sequence": "User: ",
"output_sequence": "<|end_of_turn|>\nAssistant: ",
"last_output_sequence": "",
"separator_sequence": "<|end_of_turn|>\n",
"stop_sequence": "",
"system_prompt": "You are a helpful assistant. Please answer truthfully and write out your thinking step by step to be sure you get the right answer. If you make a mistake or encounter an error in your thinking, say so out loud and attempt to correct it. If you don't know or aren't sure about something, say so clearly. You will act as a professional logician, mathematician, and physicist. You will also act as the most appropriate type of expert to answer any particular question or solve the relevant problem; state which expert type your are, if so. Also think of any particular named expert that would be ideal to answer the relevant question or solve the relevant problem; name and act as them, if appropriate.\n",
"system_sequence": "",
"wrap": false
"stop_sequence": "",
"separator_sequence": "<|end_of_turn|>\n",
"wrap": false,
"macro": true,
"names": false,
"names_force_groups": true,
"activation_regex": ""
}

View File

@ -1,13 +1,15 @@
{
"input_sequence": "\n### Instruction:",
"last_output_sequence": "\n### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):",
"macro": true,
"name": "Roleplay",
"names": true,
"output_sequence": "\n### Response:",
"separator_sequence": "",
"stop_sequence": "",
"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",
"input_sequence": "\n### Instruction:",
"output_sequence": "\n### Response:",
"last_output_sequence": "\n### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):",
"system_sequence": "",
"wrap": true
"stop_sequence": "",
"separator_sequence": "",
"wrap": true,
"macro": true,
"names": true,
"names_force_groups": true,
"activation_regex": ""
}

View File

@ -1,11 +1,15 @@
{
"name": "Vicuna 1.0",
"system_prompt": "A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions.\n\nWrite {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n",
"system_sequence": "",
"stop_sequence": "",
"input_sequence": "### Human:",
"output_sequence": "### Assistant:",
"last_output_sequence": "",
"system_sequence": "",
"stop_sequence": "",
"separator_sequence": "",
"wrap": true
"wrap": true,
"macro": true,
"names": false,
"names_force_groups": true,
"activation_regex": ""
}

View File

@ -1,11 +1,15 @@
{
"name": "Vicuna 1.1",
"system_prompt": "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.\n\nWrite {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n",
"system_sequence": "BEGINNING OF CONVERSATION:",
"stop_sequence": "",
"input_sequence": "USER: ",
"output_sequence": "ASSISTANT: ",
"last_output_sequence": "",
"system_sequence": "BEGINNING OF CONVERSATION:",
"stop_sequence": "",
"separator_sequence": "</s>",
"wrap": false
"wrap": false,
"macro": true,
"names": false,
"names_force_groups": true,
"activation_regex": ""
}

View File

@ -1,11 +1,15 @@
{
"name": "WizardLM-13B",
"system_prompt": "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.\n\nWrite {{char}}'s next detailed reply in a fictional roleplay chat between {{user}} and {{char}}.",
"system_sequence": "",
"stop_sequence": "",
"input_sequence": "USER: ",
"output_sequence": "ASSISTANT: ",
"last_output_sequence": "",
"system_sequence": "",
"stop_sequence": "",
"separator_sequence": "",
"wrap": true
"wrap": true,
"macro": true,
"names": false,
"names_force_groups": true,
"activation_regex": ""
}

View File

@ -1,11 +1,15 @@
{
"name": "WizardLM",
"system_prompt": "Write {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n",
"system_sequence": "",
"stop_sequence": "",
"input_sequence": "",
"output_sequence": "### Response:",
"last_output_sequence": "",
"system_sequence": "",
"stop_sequence": "",
"separator_sequence": "</s>",
"wrap": true
"wrap": true,
"macro": true,
"names": false,
"names_force_groups": true,
"activation_regex": ""
}

View File

@ -1,13 +1,15 @@
{
"input_sequence": "### Instruction:\n#### {{user}}:",
"last_output_sequence": "### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):\n#### {{char}}:",
"macro": true,
"name": "simple-proxy-for-tavern",
"names": false,
"system_prompt": "[System note: Write one reply only. Do not decide what {{user}} says or does. Write at least one paragraph, up to four. Be descriptive and immersive, providing vivid details about {{char}}'s actions, emotions, and the environment. Write with a high degree of complexity and burstiness. Do not repeat this message.]",
"input_sequence": "### Instruction:\n#### {{user}}:",
"output_sequence": "### Response:\n#### {{char}}:",
"separator_sequence": "",
"stop_sequence": "",
"system_prompt": "## {{char}}\n- You're \"{{char}}\" in this never-ending roleplay with \"{{user}}\".",
"last_output_sequence": "### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):\n#### {{char}}:",
"system_sequence": "",
"wrap": true
"stop_sequence": "",
"separator_sequence": "",
"wrap": true,
"macro": true,
"names": false,
"names_force_groups": false,
"activation_regex": ""
}

View File

@ -55,6 +55,7 @@ import {
renameGroupChat,
importGroupChat,
getGroupBlock,
getGroupChatNames,
} from "./scripts/group-chats.js";
import {
@ -65,9 +66,6 @@ import {
power_user,
pygmalion_options,
tokenizers,
formatInstructModeChat,
formatInstructStoryString,
formatInstructModePrompt,
persona_description_positions,
loadMovingUIState,
getCustomStoppingStrings,
@ -164,6 +162,13 @@ import { deviceInfo } from "./scripts/RossAscends-mods.js";
import { registerPromptManagerMigration } from "./scripts/PromptManager.js";
import { getRegexedString, regex_placement } from "./scripts/extensions/regex/engine.js";
import { FILTER_TYPES, FilterHelper } from "./scripts/filters.js";
import {
formatInstructModeChat,
formatInstructModePrompt,
formatInstructModeExamples,
getInstructStoppingSequences,
autoSelectInstructPreset,
} from "./scripts/instruct-mode.js";
//exporting functions and vars for mods
export {
@ -329,7 +334,6 @@ let scrollLock = false;
const durationSaveEdit = 1000;
const saveSettingsDebounced = debounce(() => saveSettings(), durationSaveEdit);
export const saveCharacterDebounced = debounce(() => $("#create_button").trigger('click'), durationSaveEdit);
const getStatusDebounced = debounce(() => getStatus(), 300_000);
const saveChatDebounced = debounce(() => saveChatConditional(), durationSaveEdit);
const system_message_types = {
@ -883,10 +887,6 @@ async function getStatus() {
const hordeStatus = await checkHordeStatus();
online_status = hordeStatus ? 'Connected' : 'no_connection';
resultCheckStatus();
if (online_status !== "no_connection") {
getStatusDebounced();
}
}
catch {
online_status = "no_connection";
@ -915,6 +915,10 @@ async function getStatus() {
if (online_status == undefined) {
online_status = "no_connection";
}
// Determine instruct mode preset
autoSelectInstructPreset(online_status);
if ((online_status.toLowerCase().indexOf("pygmalion") != -1 && power_user.pygmalion_formatting == pygmalion_options.AUTO)
|| (online_status !== "no_connection" && power_user.pygmalion_formatting == pygmalion_options.ENABLED)) {
is_pygmalion = true;
@ -936,9 +940,6 @@ async function getStatus() {
//console.log(online_status);
resultCheckStatus();
if (online_status !== "no_connection") {
getStatusDebounced();
}
},
error: function (jqXHR, exception) {
console.log(exception);
@ -1604,8 +1605,18 @@ function addOneMessage(mes, { type = "normal", insertAfter = null, scroll = true
mes.is_user,
);
const bias = messageFormatting(mes.extra?.bias ?? "");
const bookmarkLink = mes?.extra?.bookmark_link ?? '';
let bookmarkLink = mes?.extra?.bookmark_link ?? '';
// Verify bookmarked chat still exists
// Cohee: Commented out for now. I'm worried of performance issues.
/*if (bookmarkLink !== '') {
let chat_names = selected_group
? getGroupChatNames(selected_group)
: Object.values(getPastCharacterChats()).map(({ file_name }) => file_name);
if (!chat_names.includes(bookmarkLink)) {
bookmarkLink = ''
}
}*/
let params = {
mesId: count_view_mes,
characterName: characterName,
@ -1902,32 +1913,7 @@ function getStoppingStrings(isImpersonate, addSpace) {
}
}
function addInstructSequence(sequence) {
// Cohee: oobabooga's textgen always appends newline before the sequence as a stopping string
// But it's a problem for Metharme which doesn't use newlines to separate them.
const wrap = (s) => power_user.instruct.wrap ? '\n' + s : s;
// Sequence must be a non-empty string
if (typeof sequence === 'string' && sequence.length > 0) {
// If sequence is just a whitespace or newline - we don't want to make it a stopping string
// User can always add it as a custom stop string if really needed
if (sequence.trim().length > 0) {
const wrappedSequence = wrap(sequence);
// Need to respect "insert macro" setting
const stopString = power_user.instruct.macro ? substituteParams(wrappedSequence) : wrappedSequence;
result.push(stopString);
}
}
}
if (power_user.instruct.enabled) {
const input_sequence = power_user.instruct.input_sequence;
const output_sequence = power_user.instruct.output_sequence;
const last_output_sequence = power_user.instruct.last_output_sequence;
const combined_sequence = `${input_sequence}\n${output_sequence}\n${last_output_sequence}`;
combined_sequence.split('\n').filter((line, index, self) => self.indexOf(line) === index).forEach(addInstructSequence);
}
result.push(...getInstructStoppingSequences());
if (power_user.custom_stopping_strings) {
const customStoppingStrings = getCustomStoppingStrings();
@ -2069,9 +2055,8 @@ function getPersonaDescription(storyString) {
switch (power_user.persona_description_position) {
case persona_description_positions.BEFORE_CHAR:
return `${substituteParams(power_user.persona_description)}\n${storyString}`;
case persona_description_positions.AFTER_CHAR:
return `${storyString}${substituteParams(power_user.persona_description)}\n`;
return storyString;
default:
if (shouldWIAddPrompt) {
const originalAN = extension_prompts[NOTE_MODULE_NAME].value
@ -2528,11 +2513,16 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
const scenarioText = chat_metadata['scenario'] || characters[this_chid].scenario;
let charDescription = baseChatReplace(characters[this_chid].description.trim(), name1, name2);
let charPersonality = baseChatReplace(characters[this_chid].personality.trim(), name1, name2);
let personaDescription = baseChatReplace(power_user.persona_description.trim(), name1, name2);
let Scenario = baseChatReplace(scenarioText.trim(), name1, name2);
let mesExamples = baseChatReplace(characters[this_chid].mes_example.trim(), name1, name2);
let systemPrompt = power_user.prefer_character_prompt ? baseChatReplace(characters[this_chid].data?.system_prompt?.trim(), name1, name2) : '';
let jailbreakPrompt = power_user.prefer_character_jailbreak ? baseChatReplace(characters[this_chid].data?.post_history_instructions?.trim(), name1, name2) : '';
if (isInstruct) {
systemPrompt = power_user.prefer_character_prompt && systemPrompt ? systemPrompt : baseChatReplace(power_user.instruct.system_prompt, name1, name2);
}
// Parse example messages
if (!mesExamples.startsWith('<START>')) {
mesExamples = '<START>\n' + mesExamples.trim();
@ -2540,11 +2530,17 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
if (mesExamples.replace(/<START>/gi, '').trim().length === 0) {
mesExamples = '';
}
if (mesExamples && isInstruct) {
mesExamples = formatInstructModeExamples(mesExamples, name1, name2)
}
const exampleSeparator = power_user.context.example_separator ? `${power_user.context.example_separator}\n` : '';
const blockHeading = main_api === 'openai' ? '<START>\n' : exampleSeparator;
let mesExamplesArray = mesExamples.split(/<START>/gi).slice(1).map(block => `${blockHeading}${block.trim()}\n`);
if (power_user.strip_examples)
mesExamplesArray = []
// First message in fresh 1-on-1 chat reacts to user/character settings changes
if (chat.length) {
chat[0].mes = substituteParams(chat[0].mes);
@ -2571,7 +2567,9 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
const storyStringParams = {
description: charDescription,
personality: charPersonality,
persona: personaDescription,
scenario: Scenario,
system: isInstruct ? systemPrompt : '',
char: name2,
user: name1,
};
@ -2640,11 +2638,6 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
storyString = worldInfoBefore + storyString + worldInfoAfter;
}
// Format the instruction string
if (isInstruct) {
storyString = formatInstructStoryString(storyString, systemPrompt);
}
if (main_api === 'openai') {
message_already_generated = ''; // OpenAI doesn't have multigen
setOpenAIMessages(coreChat);
@ -8003,7 +7996,7 @@ $(document).ready(function () {
const enabled = $("#use-mancer-api-checkbox").prop("checked");
$("#mancer_api_subpanel").toggle(enabled);
$("#tgwebui_api_subpanel").toggle(!enabled);
api_use_mancer_webui = enabled;
saveSettingsDebounced();
getStatus();
@ -8583,8 +8576,10 @@ $(document).ready(function () {
$(document).on("click", ".mes_edit_delete", async function (event, customData) {
const fromSlashCommand = customData?.fromSlashCommand || false;
const swipeExists = (!chat[this_edit_mes_id].swipes || chat[this_edit_mes_id].swipes.length <= 1 || chat.is_user || parseInt(this_edit_mes_id) !== chat.length - 1);
if (power_user.confirm_message_delete && fromSlashCommand !== true) {
const confirmation = await callPopup("Are you sure you want to delete this message?", 'confirm');
const confirmation = swipeExists ? await callPopup("Are you sure you want to delete this message?", 'confirm')
: await callPopup("<h3>Delete this...</h3> <select id='del_type'><option value='swipe'>Swipe</option><option value='message'>Message</option></select>", 'confirm')
if (!confirmation) {
return;
}
@ -8596,10 +8591,21 @@ $(document).ready(function () {
return;
}
chat.splice(this_edit_mes_id, 1);
if ($('#del_type').val() === 'swipe') {
const swipe_id = chat[this_edit_mes_id]['swipe_id'];
chat[this_edit_mes_id]['swipes'].splice(swipe_id, 1);
if (swipe_id > 0) {
$('.swipe_left:last').click();
} else {
$('.swipe_right:last').click()
}
} else {
chat.splice(this_edit_mes_id, 1);
mes.remove();
count_view_mes--;
}
this_edit_mes_id = undefined;
mes.remove();
count_view_mes--;
updateViewMessageIds();
saveChatConditional();

View File

@ -1,3 +1,5 @@
"use strict";
import { callPopup, event_types, eventSource, is_send_press, main_api, substituteParams } from "../script.js";
import { is_group_generating } from "./group-chats.js";
import { TokenHandler } from "./openai.js";
@ -271,6 +273,8 @@ PromptManagerModule.prototype.init = function (moduleConfiguration, serviceSetti
this.serviceSettings = serviceSettings;
this.containerElement = document.getElementById(this.configuration.containerIdentifier);
if ('global' === this.configuration.promptOrder.strategy) this.activeCharacter = {id: this.configuration.promptOrder.dummyId};
this.sanitizeServiceSettings();
// Enable and disable prompts
@ -590,7 +594,7 @@ PromptManagerModule.prototype.init = function (moduleConfiguration, serviceSetti
PromptManagerModule.prototype.render = function (afterTryGenerate = true) {
if (main_api !== 'openai') return;
if (null === this.activeCharacter) return;
if ('character' === this.configuration.promptOrder.strategy && null === this.activeCharacter) return;
this.error = null;
waitUntilCondition(() => !is_send_press && !is_group_generating, 1024 * 1024, 100).then(() => {
@ -604,6 +608,11 @@ PromptManagerModule.prototype.render = function (afterTryGenerate = true) {
this.renderPromptManagerListItems()
this.makeDraggable();
this.profileEnd('render');
}).catch(error => {
this.log('Error caught during render: ' + error);
this.renderPromptManager();
this.renderPromptManagerListItems()
this.makeDraggable();
});
} else {
// Executed during live communication
@ -1155,7 +1164,6 @@ PromptManagerModule.prototype.setChatCompletion = function (chatCompletion) {
this.setMessages(messages);
this.populateTokenCounts(messages);
this.populateLegacyTokenCounts(messages);
}
/**
@ -1185,7 +1193,7 @@ PromptManagerModule.prototype.populateTokenCounts = function (messages) {
PromptManagerModule.prototype.populateLegacyTokenCounts = function (messages) {
// Update general token counts
const chatHistory = messages.getItemByIdentifier('chatHistory');
const startChat = chatHistory?.getCollection()[0].getTokens() || 0;
const startChat = chatHistory?.getCollection()[0]?.getTokens() || 0;
const continueNudge = chatHistory?.getCollection().find(message => message.identifier === 'continueNudge')?.getTokens() || 0;
this.tokenHandler.counts = {

View File

@ -380,8 +380,7 @@ async function summarizeChatMain(context, force) {
}
console.log('Summarizing chat, messages since last summary: ' + messagesSinceLastSummary, 'words since last summary: ' + wordsSinceLastSummary);
const prompt = substituteParams(extension_settings.memory.prompt)
.replace(/{{words}}/gi, extension_settings.memory.promptWords);
const prompt = extension_settings.memory.prompt?.replace(/{{words}}/gi, extension_settings.memory.promptWords);
if (!prompt) {
console.debug('Summarization prompt is empty. Skipping summarization.');

View File

@ -72,20 +72,22 @@ function getTaskByIdRecurse(taskId, task) {
return null;
}
function substituteParamsPrompts(content) {
function substituteParamsPrompts(content, substituteGlobal) {
content = content.replace(/{{objective}}/gi, currentObjective.description)
content = content.replace(/{{task}}/gi, currentTask.description)
if (currentTask.parent){
content = content.replace(/{{parent}}/gi, currentTask.parent.description)
}
content = substituteParams(content)
if (substituteGlobal) {
content = substituteParams(content)
}
return content
}
// Call Quiet Generate to create task list using character context, then convert to tasks. Should not be called much.
async function generateTasks() {
const prompt = substituteParamsPrompts(objectivePrompts.createTask);
const prompt = substituteParamsPrompts(objectivePrompts.createTask, false);
console.log(`Generating tasks for objective with prompt`)
toastr.info('Generating tasks for objective', 'Please wait...');
const taskResponse = await generateQuietPrompt(prompt)
@ -128,7 +130,7 @@ async function checkTaskCompleted() {
checkCounter = $('#objective-check-frequency').val()
toastr.info("Checking for task completion.")
const prompt = substituteParamsPrompts(objectivePrompts.checkTaskCompleted);
const prompt = substituteParamsPrompts(objectivePrompts.checkTaskCompleted, false);
const taskResponse = (await generateQuietPrompt(prompt)).toLowerCase()
// Check response if task complete
@ -178,7 +180,7 @@ function setCurrentTask(taskId = null) {
// Don't just check for a current task, check if it has data
const description = currentTask.description || null;
if (description) {
const extensionPromptText = substituteParamsPrompts(objectivePrompts.currentTask);
const extensionPromptText = substituteParamsPrompts(objectivePrompts.currentTask, true);
// Remove highlights
$('.objective-task').css({'border-color':'','border-width':''})

View File

@ -81,6 +81,7 @@ export {
regenerateGroup,
resetSelectedGroup,
select_group_chats,
getGroupChatNames,
}
let is_group_generating = false; // Group generation flag
@ -340,7 +341,7 @@ export function getGroupBlock(group) {
const template = $("#group_list_template .group_select").clone();
template.data("id", group.id);
template.attr("grid", group.id);
template.find(".ch_name").html(group.name);
template.find(".ch_name").text(group.name);
template.find('.group_fav_icon').css("display", 'none');
template.addClass(group.fav ? 'is_fav' : '');
template.find(".ch_fav").val(group.fav);
@ -370,7 +371,6 @@ function updateGroupAvatar(group) {
// check if isDataURLor if it's a valid local file url
function isValidImageUrl(url) {
console.trace(url);
// check if empty dict
if (Object.keys(url).length === 0) {
return false;
@ -419,6 +419,19 @@ function getGroupAvatar(group) {
return groupAvatar;
}
function getGroupChatNames(groupId) {
const group = groups.find(x => x.id === groupId);
if (!group) {
return [];
}
const names = [];
for (const chatId of group.chats) {
names.push(chatId);
}
return names;
}
async function generateGroupWrapper(by_auto_mode, type = null, params = {}) {
if (online_status === "no_connection") {

View File

@ -8,6 +8,8 @@ import {
import { SECRET_KEYS, writeSecret } from "./secrets.js";
import { delay } from "./utils.js";
import { deviceInfo } from "./RossAscends-mods.js";
import { power_user } from "./power-user.js";
import { autoSelectInstructPreset } from "./instruct-mode.js";
export {
horde_settings,
@ -226,19 +228,11 @@ async function showKudos() {
jQuery(function () {
$("#horde_model").on('mousedown change', async function (e) {
//desktop-only routine for multi-select without CTRL
/*if (deviceInfo.device.type === 'desktop') {
let hordeModelSelectScrollTop = null;
e.preventDefault();
const option = $(e.target);
const selectElement = $(this)[0];
hordeModelSelectScrollTop = selectElement.scrollTop;
option.prop('selected', !option.prop('selected'));
await delay(1);
selectElement.scrollTop = hordeModelSelectScrollTop;
}*/
horde_settings.models = $('#horde_model').val();
console.log('Updated Horde models', horde_settings.models);
// Try select instruct preset
autoSelectInstructPreset(horde_settings.models.join(' '));
});
$("#horde_auto_adjust_response_length").on("input", function () {

View File

@ -0,0 +1,277 @@
"use strict";
import { saveSettingsDebounced, substituteParams } from "../script.js";
import { selected_group } from "./group-chats.js";
import { power_user } from "./power-user.js";
export let instruct_presets = [];
const controls = [
{ id: "instruct_enabled", property: "enabled", isCheckbox: true },
{ id: "instruct_wrap", property: "wrap", isCheckbox: true },
{ id: "instruct_system_prompt", property: "system_prompt", isCheckbox: false },
{ id: "instruct_system_sequence", property: "system_sequence", isCheckbox: false },
{ id: "instruct_separator_sequence", property: "separator_sequence", isCheckbox: false },
{ id: "instruct_input_sequence", property: "input_sequence", isCheckbox: false },
{ id: "instruct_output_sequence", property: "output_sequence", isCheckbox: false },
{ id: "instruct_stop_sequence", property: "stop_sequence", isCheckbox: false },
{ id: "instruct_names", property: "names", isCheckbox: true },
{ id: "instruct_macro", property: "macro", isCheckbox: true },
{ id: "instruct_names_force_groups", property: "names_force_groups", isCheckbox: true },
{ id: "instruct_last_output_sequence", property: "last_output_sequence", isCheckbox: false },
{ id: "instruct_activation_regex", property: "activation_regex", isCheckbox: false },
];
/**
* Loads instruct mode settings from the given data object.
* @param {object} data Settings data object.
*/
export function loadInstructMode(data) {
if (data.instruct !== undefined) {
instruct_presets = data.instruct;
}
if (power_user.instruct.names_force_groups === undefined) {
power_user.instruct.names_force_groups = true;
}
controls.forEach(control => {
const $element = $(`#${control.id}`);
if (control.isCheckbox) {
$element.prop('checked', power_user.instruct[control.property]);
} else {
$element.val(power_user.instruct[control.property]);
}
$element.on('input', function () {
power_user.instruct[control.property] = control.isCheckbox ? !!$(this).prop('checked') : $(this).val();
saveSettingsDebounced();
});
});
instruct_presets.forEach((preset) => {
const name = preset.name;
const option = document.createElement('option');
option.value = name;
option.innerText = name;
option.selected = name === power_user.instruct.preset;
$('#instruct_presets').append(option);
});
highlightDefaultPreset();
}
function highlightDefaultPreset() {
$('#instruct_set_default').toggleClass('default', power_user.default_instruct === power_user.instruct.preset);
}
/**
* Automatically select instruct preset based on model id.
* Otherwise, if default instruct preset is set, selects it.
* @param {string} modelId Model name reported by the API.
* @returns {boolean} True if instruct preset was activated by model id, false otherwise.
*/
export function autoSelectInstructPreset(modelId) {
// If instruct mode is disabled, don't do anything
if (!power_user.instruct.enabled) {
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');
// 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`);
return true;
}
}
} 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');
}
}
return false;
}
/**
* Converts instruct mode sequences to an array of stopping strings.
* @returns {string[]} Array of instruct mode stopping strings.
*/
export function getInstructStoppingSequences() {
function addInstructSequence(sequence) {
// Cohee: oobabooga's textgen always appends newline before the sequence as a stopping string
// But it's a problem for Metharme which doesn't use newlines to separate them.
const wrap = (s) => power_user.instruct.wrap ? '\n' + s : s;
// Sequence must be a non-empty string
if (typeof sequence === 'string' && sequence.length > 0) {
// If sequence is just a whitespace or newline - we don't want to make it a stopping string
// User can always add it as a custom stop string if really needed
if (sequence.trim().length > 0) {
const wrappedSequence = wrap(sequence);
// Need to respect "insert macro" setting
const stopString = power_user.instruct.macro ? substituteParams(wrappedSequence) : wrappedSequence;
result.push(stopString);
}
}
}
const result = [];
if (power_user.instruct.enabled) {
const input_sequence = power_user.instruct.input_sequence;
const output_sequence = power_user.instruct.output_sequence;
const last_output_sequence = power_user.instruct.last_output_sequence;
const combined_sequence = `${input_sequence}\n${output_sequence}\n${last_output_sequence}`;
combined_sequence.split('\n').filter((line, index, self) => self.indexOf(line) === index).forEach(addInstructSequence);
}
return result;
}
/**
* Formats instruct mode chat message.
* @param {string} name Character name.
* @param {string} mes Message text.
* @param {boolean} isUser Is the message from the user.
* @param {boolean} isNarrator Is the message from the narrator.
* @param {string} forceAvatar Force avatar string.
* @param {string} name1 User name.
* @param {string} name2 Character name.
* @returns {string} Formatted instruct mode chat message.
*/
export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvatar, name1, name2) {
let includeNames = isNarrator ? false : power_user.instruct.names;
if (!isNarrator && power_user.instruct.names_force_groups && (selected_group || forceAvatar)) {
includeNames = true;
}
let sequence = (isUser || isNarrator) ? power_user.instruct.input_sequence : power_user.instruct.output_sequence;
if (power_user.instruct.macro) {
sequence = substituteParams(sequence, name1, name2);
}
const separator = power_user.instruct.wrap ? '\n' : '';
const separatorSequence = power_user.instruct.separator_sequence && !isUser
? power_user.instruct.separator_sequence
: separator;
const textArray = includeNames ? [sequence, `${name}: ${mes}` + separatorSequence] : [sequence, mes + separatorSequence];
const text = textArray.filter(x => x).join(separator);
return text;
}
/**
* Formats example messages according to instruct mode settings.
* @param {string} mesExamples Example messages string.
* @param {string} name1 User name.
* @param {string} name2 Character name.
* @returns {string} Formatted example messages string.
*/
export function formatInstructModeExamples(mesExamples, name1, name2) {
const includeNames = power_user.instruct.names || (!!selected_group && power_user.instruct.names_force_groups);
let inputSequence = power_user.instruct.input_sequence;
let outputSequence = power_user.instruct.output_sequence;
if (power_user.instruct.macro) {
inputSequence = substituteParams(inputSequence, name1, name2);
outputSequence = substituteParams(outputSequence, name1, name2);
}
const separator = power_user.instruct.wrap ? '\n' : '';
const separatorSequence = power_user.instruct.separator_sequence ? power_user.instruct.separator_sequence : separator;
mesExamples = mesExamples.replace(new RegExp(`\n${name1}: `, "gm"), separatorSequence + inputSequence + separator + (includeNames ? `${name1}: ` : ''));
mesExamples = mesExamples.replace(new RegExp(`\n${name2}: `, "gm"), separator + outputSequence + separator + (includeNames ? `${name2}: ` : ''));
return mesExamples;
}
/**
* Formats instruct mode last prompt line.
* @param {string} name Character name.
* @param {boolean} isImpersonate Is generation in impersonation mode.
* @param {string} promptBias Prompt bias string.
* @param {string} name1 User name.
* @param {string} name2 Character name.
*/
export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, name2) {
const includeNames = power_user.instruct.names || (!!selected_group && power_user.instruct.names_force_groups);
const getOutputSequence = () => power_user.instruct.last_output_sequence || power_user.instruct.output_sequence;
let sequence = isImpersonate ? power_user.instruct.input_sequence : getOutputSequence();
if (power_user.instruct.macro) {
sequence = substituteParams(sequence, name1, name2);
}
const separator = power_user.instruct.wrap ? '\n' : '';
let text = includeNames ? (separator + sequence + separator + `${name}:`) : (separator + sequence);
if (!isImpersonate && promptBias) {
text += (includeNames ? promptBias : (separator + promptBias));
}
return text.trimEnd() + (includeNames ? '' : separator);
}
jQuery(() => {
$('#instruct_set_default').on('click', function () {
if (power_user.instruct.preset === power_user.default_instruct) {
power_user.default_instruct = null;
$(this).removeClass('default');
toastr.info('Default instruct preset cleared');
} else {
power_user.default_instruct = power_user.instruct.preset;
$(this).addClass('default');
toastr.info(`Default instruct preset set to ${power_user.default_instruct}`);
}
saveSettingsDebounced();
});
$('#instruct_presets').on('change', function () {
const name = $(this).find(':selected').val();
const preset = instruct_presets.find(x => x.name === name);
if (!preset) {
return;
}
power_user.instruct.preset = name;
controls.forEach(control => {
if (preset[control.property] !== undefined) {
power_user.instruct[control.property] = preset[control.property];
const $element = $(`#${control.id}`);
if (control.isCheckbox) {
$element.prop('checked', power_user.instruct[control.property]).trigger('input');
} else {
$element.val(power_user.instruct[control.property]).trigger('input');
}
}
});
highlightDefaultPreset();
});
});

View File

@ -19,7 +19,6 @@ import {
system_message_types,
replaceBiasMarkup,
is_send_press,
saveSettings,
Generate,
main_api,
eventSource,
@ -219,6 +218,7 @@ const default_settings = {
proxy_password: '',
assistant_prefill: '',
use_ai21_tokenizer: false,
exclude_assistant: false,
};
const oai_settings = {
@ -260,6 +260,7 @@ const oai_settings = {
proxy_password: '',
assistant_prefill: '',
use_ai21_tokenizer: false,
exclude_assistant: false,
};
let openai_setting_names;
@ -389,7 +390,7 @@ function setupChatCompletionPromptManager(openAiSettings) {
promptManager.tokenHandler = tokenHandler;
promptManager.init(configuration, openAiSettings);
promptManager.render();
promptManager.render(false);
return promptManager;
}
@ -485,6 +486,13 @@ function populateChatHistory(prompts, chatCompletion, type = null, cyclePrompt =
const newChatMessage = new Message('system', substituteParams(newChat, null, null, null, names), 'newMainChat');
chatCompletion.reserveBudget(newChatMessage);
// Reserve budget for group nudge
let groupNudgeMessage = null;
if (selected_group) {
const groupNudgeMessage = Message.fromPrompt(prompts.get('groupNudge'));
chatCompletion.reserveBudget(groupNudgeMessage);
}
// Reserve budget for continue nudge
let continueMessage = null;
if (type === 'continue' && cyclePrompt) {
@ -526,6 +534,12 @@ function populateChatHistory(prompts, chatCompletion, type = null, cyclePrompt =
chatCompletion.freeBudget(newChatMessage);
chatCompletion.insertAtStart(newChatMessage, 'chatHistory');
// Reserve budget for group nudge
if (selected_group && groupNudgeMessage) {
chatCompletion.freeBudget(groupNudgeMessage);
chatCompletion.insertAtEnd(groupNudgeMessage, 'chatHistory');
}
// Insert and free continue nudge
if (type === 'continue' && continueMessage) {
chatCompletion.freeBudget(continueMessage);
@ -544,7 +558,10 @@ function populateDialogueExamples(prompts, chatCompletion) {
if (openai_msgs_example.length) {
const newExampleChat = new Message('system', oai_settings.new_example_chat_prompt, 'newChat');
[...openai_msgs_example].forEach((dialogue, dialogueIndex) => {
chatCompletion.insert(newExampleChat, 'dialogueExamples');
let examplesAdded = 0;
if (chatCompletion.canAfford(newExampleChat)) chatCompletion.insert(newExampleChat, 'dialogueExamples');
dialogue.forEach((prompt, promptIndex) => {
const role = 'system';
const content = prompt.content || '';
@ -554,8 +571,13 @@ function populateDialogueExamples(prompts, chatCompletion) {
chatMessage.setName(prompt.name);
if (chatCompletion.canAfford(chatMessage)) {
chatCompletion.insert(chatMessage, 'dialogueExamples');
examplesAdded++;
}
});
if (0 === examplesAdded) {
chatCompletion.removeLastFrom('dialogueExamples');
}
});
}
}
@ -697,7 +719,8 @@ function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, ty
*/
function preparePromptsForChatCompletion(Scenario, charPersonality, name2, worldInfoBefore, worldInfoAfter, charDescription, quietPrompt, bias, extensionPrompts, systemPromptOverride, jailbreakPromptOverride) {
const scenarioText = Scenario ? `[Circumstances and context of the dialogue: ${Scenario}]` : '';
const charPersonalityText = charPersonality ? `[${name2}'s personality: ${charPersonality}]` : '';
const charPersonalityText = charPersonality ? `[${name2}'s personality: ${charPersonality}]` : ''
const groupNudge = `[Write the next reply only as ${name2}]`;
// Create entries for system prompts
const systemPrompts = [
@ -711,7 +734,8 @@ function preparePromptsForChatCompletion(Scenario, charPersonality, name2, world
{ role: 'system', content: oai_settings.nsfw_avoidance_prompt, identifier: 'nsfwAvoidance' },
{ role: 'system', content: oai_settings.impersonation_prompt, identifier: 'impersonate' },
{ role: 'system', content: quietPrompt, identifier: 'quietPrompt' },
{ role: 'system', content: bias, identifier: 'bias' }
{ role: 'system', content: bias, identifier: 'bias' },
{ role: 'system', content: groupNudge, identifier: 'groupNudge' }
];
// Tavern Extras - Summary
@ -765,12 +789,6 @@ function preparePromptsForChatCompletion(Scenario, charPersonality, name2, world
prompts.set(jbReplacement, prompts.index('jailbreak'));
}
// TODO: Integrate Group nudge into the prompt manager properly
if(selected_group) {
let group_nudge = {"role": "system", "content": `[Write the next reply only as ${name2}]`};
openai_msgs.push(group_nudge);
}
// Allow subscribers to manipulate the prompts object
eventSource.emit(event_types.OAI_BEFORE_CHATCOMPLETION, prompts);
@ -1132,9 +1150,9 @@ async function sendOpenAIRequest(type, openai_msgs_tosend, signal) {
if (isClaude) {
generate_data['use_claude'] = true;
generate_data['top_k'] = parseFloat(oai_settings.top_k_openai);
generate_data['exclude_assistant'] = oai_settings.exclude_assistant;
// Don't add a prefill on quiet gens (summarization)
if (!isQuiet) {
if (!isQuiet && !oai_settings.exclude_assistant) {
generate_data['assistant_prefill'] = substituteParams(oai_settings.assistant_prefill);
}
}
@ -1153,7 +1171,7 @@ async function sendOpenAIRequest(type, openai_msgs_tosend, signal) {
generate_data['use_ai21'] = true;
generate_data['top_k'] = parseFloat(oai_settings.top_k_openai);
generate_data['count_pen'] = parseFloat(oai_settings.count_pen);
generate_data['stop_tokens'] = [name1 + ':', 'prompt: [Start a new chat]'];
generate_data['stop_tokens'] = [name1 + ':', oai_settings.new_chat_prompt, oai_settings.new_group_chat_prompt];
}
const generate_url = '/generate_openai';
@ -1665,6 +1683,21 @@ class ChatCompletion {
}
}
/**
* Remove the last item of the collection
*
* @param identifier
*/
removeLastFrom(identifier) {
const index = this.findMessageIndex(identifier);
const message = this.messages.collection[index].collection.pop();
this.increaseTokenBudgetBy(message.getTokens());
this.log(`Removed ${message.identifier} from ${identifier}. Remaining tokens: ${this.tokenBudget}`);
}
/**
* Checks if the token budget can afford the tokens of the specified message.
*
@ -1936,7 +1969,8 @@ function loadOpenAISettings(data, settings) {
if (settings.wrap_in_quotes !== undefined) oai_settings.wrap_in_quotes = !!settings.wrap_in_quotes;
if (settings.names_in_completion !== undefined) oai_settings.names_in_completion = !!settings.names_in_completion;
if (settings.openai_model !== undefined) oai_settings.openai_model = settings.openai_model;
if (settings.use_ai21_tokenizer !== undefined) oai_settings.use_ai21_tokenizer = !!settings.use_ai21_tokenizer;
if (settings.use_ai21_tokenizer !== undefined) { oai_settings.use_ai21_tokenizer = !!settings.use_ai21_tokenizer; oai_settings.use_ai21_tokenizer ? ai21_max = 8191 : ai21_max = 9200; }
if (settings.exclude_assistant !== undefined) oai_settings.exclude_assistant = !!settings.exclude_assistant;
$('#stream_toggle').prop('checked', oai_settings.stream_openai);
$('#api_url_scale').val(oai_settings.api_url_scale);
$('#openai_proxy_password').val(oai_settings.proxy_password);
@ -1966,6 +2000,7 @@ function loadOpenAISettings(data, settings) {
$('#openai_show_external_models').prop('checked', oai_settings.show_external_models);
$('#openai_external_category').toggle(oai_settings.show_external_models);
$('#use_ai21_tokenizer').prop('checked', oai_settings.use_ai21_tokenizer);
$('#exclude_assistant').prop('checked', oai_settings.exclude_assistant);
if (settings.impersonation_prompt !== undefined) oai_settings.impersonation_prompt = settings.impersonation_prompt;
$('#impersonation_prompt_textarea').val(oai_settings.impersonation_prompt);
@ -2163,6 +2198,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
show_external_models: settings.show_external_models,
assistant_prefill: settings.assistant_prefill,
use_ai21_tokenizer: settings.use_ai21_tokenizer,
exclude_assistant: settings.exclude_assistant,
};
const savePresetSettings = await fetch(`/savepreset_openai?name=${name}`, {
@ -2499,6 +2535,7 @@ function onSettingsPresetChange() {
proxy_password: ['#openai_proxy_password', 'proxy_password', false],
assistant_prefill: ['#claude_assistant_prefill', 'assistant_prefill', false],
use_ai21_tokenizer: ['#use_ai21_tokenizer', 'use_ai21_tokenizer', false],
exclude_assistant: ['#exclude_assistant', 'exclude_assistant', false],
};
const presetName = $('#settings_perset_openai').find(":selected").text();
@ -2885,6 +2922,10 @@ function toggleChatCompletionForms() {
const validSources = $(this).data('source').split(',');
$(this).toggle(validSources.includes(oai_settings.chat_completion_source));
});
if (chat_completion_sources.CLAUDE == oai_settings.chat_completion_source) {
$('#claude_assistant_prefill_block').toggle(!oai_settings.exclude_assistant);
}
}
async function testApiConnection() {
@ -2989,6 +3030,12 @@ $(document).ready(async function () {
saveSettingsDebounced();
});
$('#exclude_assistant').on('change', function () {
oai_settings.exclude_assistant = !!$('#exclude_assistant').prop('checked');
$('#claude_assistant_prefill_block').toggle(!oai_settings.exclude_assistant);
saveSettingsDebounced();
});
$('#names_in_completion').on('change', function () {
oai_settings.names_in_completion = !!$('#names_in_completion').prop('checked');
saveSettingsDebounced();

View File

@ -12,8 +12,6 @@ import {
event_types,
getCurrentChatId,
printCharacters,
name1,
name2,
setCharacterId,
setEditedMessageId
} from "../script.js";
@ -21,8 +19,8 @@ import { isMobile, initMovingUI } from "./RossAscends-mods.js";
import {
groups,
resetSelectedGroup,
selected_group,
} from "./group-chats.js";
import { loadInstructMode } from "./instruct-mode.js";
import { registerSlashCommand } from "./slash-commands.js";
@ -44,7 +42,7 @@ export {
export const MAX_CONTEXT_DEFAULT = 4096;
const MAX_CONTEXT_UNLOCKED = 65536;
const defaultStoryString = "{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}{{/if}}";
const defaultStoryString = "{{#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}}";
const defaultExampleSeparator = '***';
const defaultChatStart = '***';
@ -95,6 +93,7 @@ let power_user = {
collapse_newlines: false,
pygmalion_formatting: pygmalion_options.AUTO,
pin_examples: false,
strip_examples: false,
trim_sentences: false,
include_newline: false,
always_force_name2: false,
@ -205,7 +204,6 @@ let power_user = {
let themes = [];
let movingUIPresets = [];
let instruct_presets = [];
let context_presets = [];
const storage_keys = {
@ -665,9 +663,6 @@ function loadPowerUserSettings(settings, data) {
movingUIPresets = data.movingUIPresets;
}
if (data.instruct !== undefined) {
instruct_presets = data.instruct;
}
if (data.context !== undefined) {
context_presets = data.context;
@ -731,6 +726,7 @@ function loadPowerUserSettings(settings, data) {
$("#spoiler_free_mode").prop("checked", power_user.spoiler_free_mode);
$("#collapse-newlines-checkbox").prop("checked", power_user.collapse_newlines);
$("#pin-examples-checkbox").prop("checked", power_user.pin_examples);
$("#remove-examples-checkbox").prop("checked", power_user.strip_examples);
$("#always-force-name2-checkbox").prop("checked", power_user.always_force_name2);
$("#trim_sentences_checkbox").prop("checked", power_user.trim_sentences);
$("#include_newline_checkbox").prop("checked", power_user.include_newline);
@ -802,7 +798,7 @@ function loadPowerUserSettings(settings, data) {
$(`#character_sort_order option[data-order="${power_user.sort_order}"][data-field="${power_user.sort_field}"]`).prop("selected", true);
reloadMarkdownProcessor(power_user.render_formulas);
loadInstructMode();
loadInstructMode(data);
loadContextSettings();
loadMaxContextUnlocked();
switchWaifuMode();
@ -926,90 +922,6 @@ function loadContextSettings() {
});
}
function loadInstructMode() {
const controls = [
{ id: "instruct_enabled", property: "enabled", isCheckbox: true },
{ id: "instruct_wrap", property: "wrap", isCheckbox: true },
{ id: "instruct_system_prompt", property: "system_prompt", isCheckbox: false },
{ id: "instruct_system_sequence", property: "system_sequence", isCheckbox: false },
{ id: "instruct_separator_sequence", property: "separator_sequence", isCheckbox: false },
{ id: "instruct_input_sequence", property: "input_sequence", isCheckbox: false },
{ id: "instruct_output_sequence", property: "output_sequence", isCheckbox: false },
{ id: "instruct_stop_sequence", property: "stop_sequence", isCheckbox: false },
{ id: "instruct_names", property: "names", isCheckbox: true },
{ id: "instruct_macro", property: "macro", isCheckbox: true },
{ id: "instruct_names_force_groups", property: "names_force_groups", isCheckbox: true },
{ id: "instruct_last_output_sequence", property: "last_output_sequence", isCheckbox: false },
{ id: "instruct_activation_regex", property: "activation_regex", isCheckbox: false },
];
if (power_user.instruct.names_force_groups === undefined) {
power_user.instruct.names_force_groups = true;
}
controls.forEach(control => {
const $element = $(`#${control.id}`);
if (control.isCheckbox) {
$element.prop('checked', power_user.instruct[control.property]);
} else {
$element.val(power_user.instruct[control.property]);
}
$element.on('input', function () {
power_user.instruct[control.property] = control.isCheckbox ? !!$(this).prop('checked') : $(this).val();
saveSettingsDebounced();
});
});
instruct_presets.forEach((preset) => {
const name = preset.name;
const option = document.createElement('option');
option.value = name;
option.innerText = name;
option.selected = name === power_user.instruct.preset;
$('#instruct_presets').append(option);
});
function highlightDefaultPreset() {
$('#instruct_set_default').toggleClass('default', power_user.default_instruct === power_user.instruct.preset);
}
$('#instruct_set_default').on('click', function () {
power_user.default_instruct = power_user.instruct.preset;
$(this).addClass('default');
toastr.success(`Default instruct preset set to ${power_user.default_instruct}`);
saveSettingsDebounced();
});
highlightDefaultPreset();
$('#instruct_presets').on('change', function () {
const name = $(this).find(':selected').val();
const preset = instruct_presets.find(x => x.name === name);
if (!preset) {
return;
}
power_user.instruct.preset = name;
controls.forEach(control => {
if (preset[control.property] !== undefined) {
power_user.instruct[control.property] = preset[control.property];
const $element = $(`#${control.id}`);
if (control.isCheckbox) {
$element.prop('checked', power_user.instruct[control.property]).trigger('input');
} else {
$element.val(power_user.instruct[control.property]).trigger('input');
}
}
});
highlightDefaultPreset();
});
}
export function fuzzySearchCharacters(searchValue) {
const fuse = new Fuse(characters, {
keys: [
@ -1066,58 +978,6 @@ export function renderStoryString(params) {
}
}
export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvatar, name1, name2) {
let includeNames = isNarrator ? false : power_user.instruct.names;
if (!isNarrator && power_user.instruct.names_force_groups && (selected_group || forceAvatar)) {
includeNames = true;
}
let sequence = (isUser || isNarrator) ? power_user.instruct.input_sequence : power_user.instruct.output_sequence;
if (power_user.instruct.macro) {
sequence = substituteParams(sequence, name1, name2);
}
const separator = power_user.instruct.wrap ? '\n' : '';
const separatorSequence = power_user.instruct.separator_sequence && !isUser
? power_user.instruct.separator_sequence
: separator;
const textArray = includeNames ? [sequence, `${name}: ${mes}` + separatorSequence] : [sequence, mes + separatorSequence];
const text = textArray.filter(x => x).join(separator);
return text;
}
export function formatInstructStoryString(story, systemPrompt) {
// If the character has a custom system prompt AND user has it preferred, use that instead of the default
systemPrompt = power_user.prefer_character_prompt && systemPrompt ? systemPrompt : power_user.instruct.system_prompt;
const sequence = power_user.instruct.system_sequence || '';
const prompt = substituteParams(systemPrompt, name1, name2, power_user.instruct.system_prompt) || '';
const separator = power_user.instruct.wrap ? '\n' : '';
const textArray = [sequence, prompt + '\n' + story];
const text = textArray.filter(x => x).join(separator);
return text;
}
export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, name2) {
const includeNames = power_user.instruct.names || (!!selected_group && power_user.instruct.names_force_groups);
const getOutputSequence = () => power_user.instruct.last_output_sequence || power_user.instruct.output_sequence;
let sequence = isImpersonate ? power_user.instruct.input_sequence : getOutputSequence();
if (power_user.instruct.macro) {
sequence = substituteParams(sequence, name1, name2);
}
const separator = power_user.instruct.wrap ? '\n' : '';
let text = includeNames ? (separator + sequence + separator + `${name}:`) : (separator + sequence);
if (!isImpersonate && promptBias) {
text += (includeNames ? promptBias : (separator + promptBias));
}
return text.trimEnd() + (includeNames ? '' : separator);
}
const sortFunc = (a, b) => power_user.sort_order == 'asc' ? compareFunc(a, b) : compareFunc(b, a);
const compareFunc = (first, second) => {
if (power_user.sort_order == 'random') {
@ -1693,10 +1553,27 @@ $(document).ready(() => {
});
$("#pin-examples-checkbox").change(function () {
if ($(this).prop("checked")) {
$("#remove-examples-checkbox").prop("checked", false).prop("disabled", true);
power_user.strip_examples = false;
} else {
$("#remove-examples-checkbox").prop("disabled", false);
}
power_user.pin_examples = !!$(this).prop("checked");
saveSettingsDebounced();
});
$("#remove-examples-checkbox").change(function () {
if ($(this).prop("checked")) {
$("#pin-examples-checkbox").prop("checked", false).prop("disabled", true);
power_user.pin_examples = false;
} else {
$("#pin-examples-checkbox").prop("disabled", false);
}
power_user.strip_examples = !!$(this).prop("checked");
saveSettingsDebounced();
});
// include newline is the child of trim sentences
// if include newline is checked, trim sentences must be checked
// if trim sentences is unchecked, include newline must be unchecked

View File

@ -16,13 +16,15 @@ import {
this_chid,
} from "../script.js";
import { groups, selected_group } from "./group-chats.js";
import { instruct_presets } from "./instruct-mode.js";
import { kai_settings } from "./kai-settings.js";
import { power_user } from "./power-user.js";
import {
textgenerationwebui_preset_names,
textgenerationwebui_presets,
textgenerationwebui_settings,
} from "./textgen-settings.js";
import { download, parseJsonFile, waitUntilCondition } from "./utils.js";
import { deepClone, download, parseJsonFile, waitUntilCondition } from "./utils.js";
const presetManagers = {};
@ -55,8 +57,10 @@ function autoSelectPreset() {
}
}
function getPresetManager() {
const apiId = main_api == 'koboldhorde' ? 'kobold' : main_api;
function getPresetManager(apiId) {
if (!apiId) {
apiId = main_api == 'koboldhorde' ? 'kobold' : main_api;
}
if (!Object.keys(presetManagers).includes(apiId)) {
return null;
@ -162,6 +166,10 @@ class PresetManager {
presets = textgenerationwebui_presets;
preset_names = textgenerationwebui_preset_names;
break;
case "instruct":
presets = instruct_presets;
preset_names = instruct_presets.map(x => x.name);
break;
default:
console.warn(`Unknown API ID ${this.apiId}`);
}
@ -169,12 +177,20 @@ class PresetManager {
return { presets, preset_names };
}
isKeyedApi() {
return this.apiId == "textgenerationwebui" || this.apiId == "instruct";
}
isNonGenericApi() {
return this.apiId == "instruct";
}
updateList(name, preset) {
const { presets, preset_names } = this.getPresetList();
const presetExists = this.apiId == "textgenerationwebui" ? preset_names.includes(name) : Object.keys(preset_names).includes(name);
const presetExists = this.isKeyedApi() ? preset_names.includes(name) : Object.keys(preset_names).includes(name);
if (presetExists) {
if (this.apiId == "textgenerationwebui") {
if (this.isKeyedApi()) {
presets[preset_names.indexOf(name)] = preset;
$(this.select).find(`option[value="${name}"]`).prop('selected', true);
$(this.select).val(name).trigger("change");
@ -189,8 +205,8 @@ class PresetManager {
else {
presets.push(preset);
const value = presets.length - 1;
// ooba is reversed
if (this.apiId == "textgenerationwebui") {
if (this.isKeyedApi()) {
preset_names[value] = name;
const option = $('<option></option>', { value: name, text: name, selected: true });
$(this.select).append(option);
@ -214,6 +230,10 @@ class PresetManager {
return nai_settings;
case "textgenerationwebui":
return textgenerationwebui_settings;
case "instruct":
const preset = deepClone(power_user.instruct);
preset['name'] = power_user.instruct.preset;
return preset;
default:
console.warn(`Unknown API ID ${apiId}`);
return {};
@ -229,6 +249,7 @@ class PresetManager {
'streaming_novel',
'nai_preamble',
'model_novel',
"enabled",
];
const settings = Object.assign({}, getSettingsByApiId(this.apiId));
@ -238,8 +259,10 @@ class PresetManager {
}
}
settings['genamt'] = amount_gen;
settings['max_length'] = max_context;
if (!this.isNonGenericApi()) {
settings['genamt'] = amount_gen;
settings['max_length'] = max_context;
}
return settings;
}
@ -256,7 +279,7 @@ class PresetManager {
$(this.select).find(`option[value="${value}"]`).remove();
if (this.apiId == "textgenerationwebui") {
if (this.isKeyedApi()) {
preset_names.splice(preset_names.indexOf(value), 1);
} else {
delete preset_names[nameToDelete];
@ -289,9 +312,11 @@ jQuery(async () => {
eventSource.on(event_types.CHAT_CHANGED, autoSelectPreset);
registerPresetManagers();
$(document).on("click", "[data-preset-manager-update]", async function () {
const presetManager = getPresetManager();
const apiId = $(this).data("preset-manager-update");
const presetManager = getPresetManager(apiId);
if (!presetManager) {
console.warn(`Preset Manager not found for API: ${apiId}`);
return;
}
@ -299,9 +324,11 @@ jQuery(async () => {
});
$(document).on("click", "[data-preset-manager-new]", async function () {
const presetManager = getPresetManager();
const apiId = $(this).data("preset-manager-new");
const presetManager = getPresetManager(apiId);
if (!presetManager) {
console.warn(`Preset Manager not found for API: ${apiId}`);
return;
}
@ -309,9 +336,11 @@ jQuery(async () => {
});
$(document).on("click", "[data-preset-manager-export]", async function () {
const presetManager = getPresetManager();
const apiId = $(this).data("preset-manager-export");
const presetManager = getPresetManager(apiId);
if (!presetManager) {
console.warn(`Preset Manager not found for API: ${apiId}`);
return;
}
@ -323,13 +352,16 @@ jQuery(async () => {
});
$(document).on("click", "[data-preset-manager-import]", async function () {
$('[data-preset-manager-file]').trigger('click');
const apiId = $(this).data("preset-manager-import");
$(`[data-preset-manager-file="${apiId}"]`).trigger('click');
});
$(document).on("change", "[data-preset-manager-file]", async function (e) {
const presetManager = getPresetManager();
const apiId = $(this).data("preset-manager-file");
const presetManager = getPresetManager(apiId);
if (!presetManager) {
console.warn(`Preset Manager not found for API: ${apiId}`);
return;
}
@ -348,9 +380,11 @@ jQuery(async () => {
});
$(document).on("click", "[data-preset-manager-delete]", async function () {
const presetManager = getPresetManager();
const apiId = $(this).data("preset-manager-delete");
const presetManager = getPresetManager(apiId);
if (!presetManager) {
console.warn(`Preset Manager not found for API: ${apiId}`);
return;
}

View File

@ -464,7 +464,7 @@ function appendWorldEntry(name, data, entry) {
const contentInput = template.find('textarea[name="content"]');
contentInput.data("uid", entry.uid);
contentInput.on("input", function (_, { skipCount }) {
contentInput.on("input", function (_, { skipCount } = {}) {
const uid = $(this).data("uid");
const value = $(this).val();
data.entries[uid].content = value;

View File

@ -35,7 +35,10 @@
--cobalt30a: rgba(100, 100, 255, 0.3);
--greyCAIbg: rgb(36, 36, 37);
--ivory: rgb(220, 220, 210);
--golden: rgba(212, 175, 55, 1);
--golden: rgb(248, 211, 0);
--warning: rgba(255, 0, 0, 0.9);
--active: rgb(88, 182, 0);
--preferred: rgb(244, 67, 54);
/*Default Theme, will be changed by ToolCool Color Picker*/
@ -54,7 +57,7 @@
/* 800px; */
/*base variable calculated in rems*/
--fontScale: 1;
--mainFontSize: calc(var(--fontScale) * 1rem);
--mainFontSize: calc(var(--fontScale) * 14px);
/* base variable for blur strength slider calculations */
--blurStrength: 10;
@ -228,7 +231,7 @@ table.responsiveTable {
display: block;
font-size: calc(var(--mainFontSize) - 0.1rem);
font-weight: 500;
color: darkgoldenrod;
color: var(--SmartThemeQuoteColor);
}
.mes_text i,
@ -1168,7 +1171,7 @@ input[type="file"] {
#extension_floating_counter {
font-weight: 600;
color: orange;
color: var(--SmartThemeQuoteColor);
}
.extension_token_counter {
@ -1250,19 +1253,15 @@ select option:not(:checked) {
}
.fav_on {
color: #c5b457 !important;
color: var(--golden) !important;
}
.world_set {
color: #4b9c00 !important;
}
#instruct_set_default {
font-size: smaller;
color: var(--active) !important;
}
#instruct_set_default.default {
color: #f44336 !important;
color: var(--preferred) !important;
}
.displayBlock {
@ -1280,7 +1279,7 @@ select option:not(:checked) {
#api_button:hover,
#api_button_novel:hover,
#api_button_textgenerationwebui:hover {
background-color: green;
background-color: var(--active);
}
.api-load-icon {
@ -1554,7 +1553,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
.ch_fav_icon {
filter: drop-shadow(1px 1px 2px black);
color: #c5b457;
color: var(--golden);
font-size: 14px;
order: -1;
margin-left: -75px;
@ -1566,7 +1565,13 @@ input[type=search]:focus::-webkit-search-cancel-button {
.character_select.is_fav .avatar,
.group_select.is_fav .avatar,
.group_member.is_fav .avatar {
outline: 2px solid #c5b457;
outline: 2px solid var(--golden);
}
.character_select.is_fav .ch_name,
.group_select.is_fav .ch_name,
.group_member.is_fav .ch_name {
color: var(--golden);
}
#fav_chara_wrap {
@ -2754,7 +2759,7 @@ body .ui-widget-content li:hover {
}
span.warning {
color: rgba(255, 0, 0, 0.5);
color: var(--warning);
font-weight: bolder;
}
@ -3315,8 +3320,8 @@ a {
}
.reverse_proxy_warning {
color: red;
background-color: black;
color: var(--warning);
background-color: var(--black70a);
text-shadow: none !important;
margin-top: 12px !important;
border-radius: 5px;
@ -3325,7 +3330,7 @@ a {
}
.neutral_warning {
color: rgba(225, 0, 0, 0.9);
color: var(--warning);
font-weight: 800;
}
@ -3359,7 +3364,7 @@ a {
width: calc((100vw - var(--sheldWidth)) /2);
position: absolute;
padding: 0;
filter: drop-shadow(2px 2px 2px #51515199);
filter: drop-shadow(2px 2px 2px var(--grey7070a));
z-index: 29;
overflow: hidden;
display: none;
@ -3485,7 +3490,7 @@ a {
background-color: transparent;
border: none;
outline: none;
color: white;
color: var(--SmartThemeBodyColor);
display: inline-block;
/* Change display to inline-block */
vertical-align: middle;
@ -3495,4 +3500,4 @@ a {
z-index: 10;
margin-left: 10px;
/* Give some space between the button and search box */
}
}

View File

@ -3318,9 +3318,9 @@ async function sendClaudeRequest(request, response) {
controller.abort();
});
let requestPrompt = convertClaudePrompt(request.body.messages, true, true);
let requestPrompt = convertClaudePrompt(request.body.messages, true, !request.body.exclude_assistant);
if (request.body.assistant_prefill) {
if (request.body.assistant_prefill && !request.body.exclude_assistant) {
requestPrompt += request.body.assistant_prefill;
}
@ -3680,14 +3680,14 @@ app.post("/save_preset", jsonParser, function (request, response) {
return response.sendStatus(400);
}
const filename = `${name}.settings`;
const directory = getPresetFolderByApiId(request.body.apiId);
const settings = getPresetSettingsByAPI(request.body.apiId);
const filename = name + settings.extension;
if (!directory) {
if (!settings.folder) {
return response.sendStatus(400);
}
const fullpath = path.join(directory, filename);
const fullpath = path.join(settings.folder, filename);
writeFileAtomicSync(fullpath, JSON.stringify(request.body.preset, null, 4), 'utf-8');
return response.send({ name });
});
@ -3698,16 +3698,16 @@ app.post("/delete_preset", jsonParser, function (request, response) {
return response.sendStatus(400);
}
const filename = `${name}.settings`;
const directory = getPresetFolderByApiId(request.body.apiId);
const settings = getPresetSettingsByAPI(request.body.apiId);
const filename = name + settings.extension;
if (!directory) {
if (!settings.folder) {
return response.sendStatus(400);
}
const fullpath = path.join(directory, filename);
const fullpath = path.join(settings.folder, filename);
if (fs.existsSync) {
if (fs.existsSync(fullpath)) {
fs.unlinkSync(fullpath);
return response.sendStatus(200);
} else {
@ -3727,17 +3727,19 @@ app.post("/savepreset_openai", jsonParser, function (request, response) {
return response.send({ name });
});
function getPresetFolderByApiId(apiId) {
function getPresetSettingsByAPI(apiId) {
switch (apiId) {
case 'kobold':
case 'koboldhorde':
return directories.koboldAI_Settings;
return { folder: directories.koboldAI_Settings, extension: '.settings' };
case 'novel':
return directories.novelAI_Settings;
return { folder: directories.novelAI_Settings, extension: '.settings' };
case 'textgenerationwebui':
return directories.textGen_Settings;
return { folder: directories.textGen_Settings, extension: '.settings' };
case 'instruct':
return { folder: directories.instruct, extension: '.json' };
default:
return null;
return { folder: null, extension: null };
}
}