mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
(Beta) Add instruct mode #250
This commit is contained in:
@ -1150,7 +1150,7 @@
|
||||
</a>
|
||||
</h3>
|
||||
<div class="flex-container">
|
||||
<div name="PygOverrides">
|
||||
<div name="PygOverrides" class="flex1">
|
||||
<h4>AutoFormat Overrides</h4>
|
||||
<label class="checkbox_label" for="disable-description-formatting-checkbox">
|
||||
<input id="disable-description-formatting-checkbox" type="checkbox" />
|
||||
@ -1180,28 +1180,45 @@
|
||||
<input id="custom_chat_separator" class="text_pole" type="text" placeholder="<START>" maxlength="100" />
|
||||
</div>
|
||||
</div>
|
||||
<div id="anchors-block">
|
||||
<h4>
|
||||
Anchors Order
|
||||
<a href="/notes#anchors" class="notes-link" target="_blank">
|
||||
<span class="note-link-span">?</span>
|
||||
</a>
|
||||
</h4>
|
||||
<select id="anchor_order">
|
||||
<option value="0">Character then Style</option>
|
||||
<option value="1">Style then Character</option>
|
||||
</select>
|
||||
<div id="anchor_checkbox">
|
||||
<label for="character_anchor"><input id="character_anchor" type="checkbox" />
|
||||
Character Anchor
|
||||
<div>
|
||||
<h4>Instruct mode</h4>
|
||||
<label for="instruct_enabled" class="checkbox_label">
|
||||
<input id="instruct_enabled" type="checkbox" />
|
||||
Enabled
|
||||
</label>
|
||||
<label for="style_anchor"><input id="style_anchor" type="checkbox" />
|
||||
Style Anchor
|
||||
<label>
|
||||
System Prompt
|
||||
</label>
|
||||
<textarea id="instruct_system_prompt" class="text_pole textarea_compact"></textarea>
|
||||
<label for="instruct_system_sequence">
|
||||
System Sequence
|
||||
</label>
|
||||
<div>
|
||||
<input id="instruct_system_sequence" class="text_pole textarea_compact" type="text" maxlength="100" />
|
||||
</div>
|
||||
<label for="instruct_input_sequence">
|
||||
Input Sequence
|
||||
</label>
|
||||
<div>
|
||||
<input id="instruct_input_sequence" class="text_pole textarea_compact" type="text" maxlength="100" />
|
||||
</div>
|
||||
<label for="instruct_output_sequence">
|
||||
Output Sequence
|
||||
</label>
|
||||
<div>
|
||||
<input id="instruct_output_sequence" class="text_pole textarea_compact" type="text" maxlength="100" />
|
||||
</div>
|
||||
<label for="instruct_wrap" class="checkbox_label">
|
||||
<input id="instruct_wrap" type="checkbox" />
|
||||
Wrap Sequences with Newline
|
||||
</label>
|
||||
<label for="instruct_names" class="checkbox_label">
|
||||
<input id="instruct_names" type="checkbox" />
|
||||
Include Names
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div name="ContextFormatting">
|
||||
<div name="ContextFormatting" class="flex1">
|
||||
<h4>Context Formatting</h4>
|
||||
<div>
|
||||
<h4>Tokenizer
|
||||
@ -1268,6 +1285,26 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="anchors-block">
|
||||
<h4>
|
||||
Anchors Order
|
||||
<a href="/notes#anchors" class="notes-link" target="_blank">
|
||||
<span class="note-link-span">?</span>
|
||||
</a>
|
||||
</h4>
|
||||
<select id="anchor_order">
|
||||
<option value="0">Character then Style</option>
|
||||
<option value="1">Style then Character</option>
|
||||
</select>
|
||||
<div id="anchor_checkbox">
|
||||
<label for="character_anchor"><input id="character_anchor" type="checkbox" />
|
||||
Character Anchor
|
||||
</label>
|
||||
<label for="style_anchor"><input id="style_anchor" type="checkbox" />
|
||||
Style Anchor
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -60,6 +60,9 @@ import {
|
||||
power_user,
|
||||
pygmalion_options,
|
||||
tokenizers,
|
||||
formatInstructModeChat,
|
||||
formatInstructStoryString,
|
||||
formatInstructModePrompt,
|
||||
} from "./scripts/power-user.js";
|
||||
|
||||
import {
|
||||
@ -1218,6 +1221,15 @@ function getStoppingStrings(isImpersonate, addSpace) {
|
||||
}
|
||||
}
|
||||
|
||||
if (power_user.instruct.enabled) {
|
||||
if (power_user.instruct.input_sequence) {
|
||||
result.push(`\n${power_user.instruct.input_sequence}`);
|
||||
}
|
||||
if (power_user.instruct.output_sequence) {
|
||||
result.push(`\n${power_user.instruct.output_sequence}`);
|
||||
}
|
||||
}
|
||||
|
||||
return addSpace ? result.map(x => `${x} `) : result;
|
||||
}
|
||||
|
||||
@ -1542,6 +1554,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
generation_started = new Date();
|
||||
|
||||
const isImpersonate = type == "impersonate";
|
||||
const isInstruct = power_user.instruct.enabled;
|
||||
message_already_generated = isImpersonate ? `${name1}: ` : `${name2}: `;
|
||||
|
||||
const interruptedByCommand = processCommands($("#send_textarea").val(), type);
|
||||
@ -1720,6 +1733,10 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
force_name2 = false;
|
||||
}
|
||||
|
||||
if (isInstruct) {
|
||||
storyString = formatInstructStoryString(storyString);
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
|
||||
let chat2 = [];
|
||||
@ -1733,7 +1750,6 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
let charName = selected_group ? coreChat[j].name : name2;
|
||||
let this_mes_ch_name = '';
|
||||
if (coreChat[j]['is_user']) {
|
||||
//this_mes_ch_name = name1;
|
||||
this_mes_ch_name = coreChat[j]['name'];
|
||||
} else {
|
||||
this_mes_ch_name = charName;
|
||||
@ -1744,10 +1760,12 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
chat2[i] = coreChat[j]['mes'] + '\n';
|
||||
}
|
||||
|
||||
if (isInstruct) {
|
||||
chat2[i] = formatInstructModeChat(this_mes_ch_name, coreChat[j]['mes'], coreChat[j]['is_user']);
|
||||
}
|
||||
|
||||
// replace bias markup
|
||||
//chat2[i] = (chat2[i] ?? '').replace(/{.*}/g, '');
|
||||
chat2[i] = (chat2[i] ?? '').replace(/{{(\*?.*\*?)}}/g, '');
|
||||
//console.log('replacing chat2 {}s');
|
||||
}
|
||||
//chat2 = chat2.reverse();
|
||||
|
||||
@ -1904,7 +1922,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
item += anchorBottom + "\n";
|
||||
}
|
||||
}
|
||||
if (is_pygmalion) {
|
||||
if (is_pygmalion && !isInstruct) {
|
||||
if (i === arrMes.length - 1 && item.trim().startsWith(name1 + ":")) {//for add name2 when user sent
|
||||
item = item + name2 + ":";
|
||||
}
|
||||
@ -1951,9 +1969,14 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
mesExmString = pinExmString ?? mesExamplesArray.slice(0, count_exm_add).join('');
|
||||
mesSendString = '';
|
||||
for (let j = 0; j < mesSend.length; j++) {
|
||||
|
||||
const isBottom = j === mesSend.length - 1;
|
||||
mesSendString += mesSend[j];
|
||||
if (isImpersonate && j === mesSend.length - 1 && tokens_already_generated === 0) {
|
||||
|
||||
if (isInstruct && isBottom && tokens_already_generated === 0) {
|
||||
mesSendString += formatInstructModePrompt(isImpersonate);
|
||||
}
|
||||
|
||||
if (!isInstruct && isImpersonate && isBottom && tokens_already_generated === 0) {
|
||||
const name = is_pygmalion ? 'You' : name1;
|
||||
if (!mesSendString.endsWith('\n')) {
|
||||
mesSendString += '\n';
|
||||
@ -1961,7 +1984,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
mesSendString += name + ':';
|
||||
}
|
||||
|
||||
if (force_name2 && j === mesSend.length - 1 && tokens_already_generated === 0) {
|
||||
if (force_name2 && isBottom && tokens_already_generated === 0) {
|
||||
if (!mesSendString.endsWith('\n')) {
|
||||
mesSendString += '\n';
|
||||
}
|
||||
|
@ -7,9 +7,11 @@ import {
|
||||
reloadMarkdownProcessor,
|
||||
reloadCurrentChat,
|
||||
getRequestHeaders,
|
||||
substituteParams,
|
||||
} from "../script.js";
|
||||
import {
|
||||
groups,
|
||||
selected_group,
|
||||
} from "./group-chats.js";
|
||||
|
||||
export {
|
||||
@ -109,6 +111,16 @@ let power_user = {
|
||||
allow_name2_display: false,
|
||||
hotswap_enabled: true,
|
||||
timer_enabled: true,
|
||||
|
||||
instruct: {
|
||||
enabled: false,
|
||||
wrap: true,
|
||||
names: false,
|
||||
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}}. Write 1 reply only.",
|
||||
system_sequence: '',
|
||||
input_sequence: '### Instruction:',
|
||||
output_sequence: '### Response:',
|
||||
}
|
||||
};
|
||||
|
||||
let themes = [];
|
||||
@ -514,6 +526,59 @@ function loadPowerUserSettings(settings, data) {
|
||||
$(`#character_sort_order option[data-order="${power_user.sort_order}"][data-field="${power_user.sort_field}"]`).prop("selected", true);
|
||||
sortCharactersList();
|
||||
reloadMarkdownProcessor(power_user.render_formulas);
|
||||
loadInstructMode();
|
||||
}
|
||||
|
||||
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_input_sequence", property: "input_sequence", isCheckbox: false },
|
||||
{ id: "instruct_output_sequence", property: "output_sequence", isCheckbox: false },
|
||||
{ id: "instruct_names", property: "names", isCheckbox: 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();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function formatInstructModeChat(name, mes, isUser) {
|
||||
const includeNames = power_user.instruct.names || (selected_group && !isUser);
|
||||
const sequence = isUser ? power_user.instruct.input_sequence : power_user.instruct.output_sequence;
|
||||
const separator = power_user.instruct.wrap ? '\n' : '';
|
||||
const textArray = includeNames ? [sequence, name, ': ', mes, separator] : [sequence, mes, separator];
|
||||
const text = textArray.filter(x => x).join(separator);
|
||||
return text;
|
||||
}
|
||||
|
||||
export function formatInstructStoryString(story) {
|
||||
const sequence = power_user.instruct.system_sequence || '';
|
||||
const prompt = substituteParams(power_user.instruct.system_prompt) || '';
|
||||
const separator = power_user.instruct.wrap ? '\n' : '';
|
||||
const textArray = [sequence, prompt, story, separator];
|
||||
const text = textArray.filter(x => x).join(separator);
|
||||
return text;
|
||||
}
|
||||
|
||||
export function formatInstructModePrompt(isImpersonate) {
|
||||
const sequence = isImpersonate ? power_user.instruct.input_sequence : power_user.instruct.output_sequence;
|
||||
const separator = power_user.instruct.wrap ? '\n' : '';
|
||||
const text = separator + sequence;
|
||||
return text;
|
||||
}
|
||||
|
||||
const sortFunc = (a, b) => power_user.sort_order == 'asc' ? compareFunc(a, b) : compareFunc(b, a);
|
||||
|
Reference in New Issue
Block a user