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>
|
</a>
|
||||||
</h3>
|
</h3>
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<div name="PygOverrides">
|
<div name="PygOverrides" class="flex1">
|
||||||
<h4>AutoFormat Overrides</h4>
|
<h4>AutoFormat Overrides</h4>
|
||||||
<label class="checkbox_label" for="disable-description-formatting-checkbox">
|
<label class="checkbox_label" for="disable-description-formatting-checkbox">
|
||||||
<input id="disable-description-formatting-checkbox" type="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" />
|
<input id="custom_chat_separator" class="text_pole" type="text" placeholder="<START>" maxlength="100" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="anchors-block">
|
<div>
|
||||||
<h4>
|
<h4>Instruct mode</h4>
|
||||||
Anchors Order
|
<label for="instruct_enabled" class="checkbox_label">
|
||||||
<a href="/notes#anchors" class="notes-link" target="_blank">
|
<input id="instruct_enabled" type="checkbox" />
|
||||||
<span class="note-link-span">?</span>
|
Enabled
|
||||||
</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>
|
||||||
<label for="style_anchor"><input id="style_anchor" type="checkbox" />
|
<label>
|
||||||
Style Anchor
|
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>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div name="ContextFormatting" class="flex1">
|
||||||
<div name="ContextFormatting">
|
|
||||||
<h4>Context Formatting</h4>
|
<h4>Context Formatting</h4>
|
||||||
<div>
|
<div>
|
||||||
<h4>Tokenizer
|
<h4>Tokenizer
|
||||||
@ -1268,6 +1285,26 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -60,6 +60,9 @@ import {
|
|||||||
power_user,
|
power_user,
|
||||||
pygmalion_options,
|
pygmalion_options,
|
||||||
tokenizers,
|
tokenizers,
|
||||||
|
formatInstructModeChat,
|
||||||
|
formatInstructStoryString,
|
||||||
|
formatInstructModePrompt,
|
||||||
} from "./scripts/power-user.js";
|
} from "./scripts/power-user.js";
|
||||||
|
|
||||||
import {
|
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;
|
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();
|
generation_started = new Date();
|
||||||
|
|
||||||
const isImpersonate = type == "impersonate";
|
const isImpersonate = type == "impersonate";
|
||||||
|
const isInstruct = power_user.instruct.enabled;
|
||||||
message_already_generated = isImpersonate ? `${name1}: ` : `${name2}: `;
|
message_already_generated = isImpersonate ? `${name1}: ` : `${name2}: `;
|
||||||
|
|
||||||
const interruptedByCommand = processCommands($("#send_textarea").val(), type);
|
const interruptedByCommand = processCommands($("#send_textarea").val(), type);
|
||||||
@ -1720,6 +1733,10 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
force_name2 = false;
|
force_name2 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isInstruct) {
|
||||||
|
storyString = formatInstructStoryString(storyString);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
|
|
||||||
let chat2 = [];
|
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 charName = selected_group ? coreChat[j].name : name2;
|
||||||
let this_mes_ch_name = '';
|
let this_mes_ch_name = '';
|
||||||
if (coreChat[j]['is_user']) {
|
if (coreChat[j]['is_user']) {
|
||||||
//this_mes_ch_name = name1;
|
|
||||||
this_mes_ch_name = coreChat[j]['name'];
|
this_mes_ch_name = coreChat[j]['name'];
|
||||||
} else {
|
} else {
|
||||||
this_mes_ch_name = charName;
|
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';
|
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
|
// replace bias markup
|
||||||
//chat2[i] = (chat2[i] ?? '').replace(/{.*}/g, '');
|
|
||||||
chat2[i] = (chat2[i] ?? '').replace(/{{(\*?.*\*?)}}/g, '');
|
chat2[i] = (chat2[i] ?? '').replace(/{{(\*?.*\*?)}}/g, '');
|
||||||
//console.log('replacing chat2 {}s');
|
|
||||||
}
|
}
|
||||||
//chat2 = chat2.reverse();
|
//chat2 = chat2.reverse();
|
||||||
|
|
||||||
@ -1904,7 +1922,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
item += anchorBottom + "\n";
|
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
|
if (i === arrMes.length - 1 && item.trim().startsWith(name1 + ":")) {//for add name2 when user sent
|
||||||
item = item + name2 + ":";
|
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('');
|
mesExmString = pinExmString ?? mesExamplesArray.slice(0, count_exm_add).join('');
|
||||||
mesSendString = '';
|
mesSendString = '';
|
||||||
for (let j = 0; j < mesSend.length; j++) {
|
for (let j = 0; j < mesSend.length; j++) {
|
||||||
|
const isBottom = j === mesSend.length - 1;
|
||||||
mesSendString += mesSend[j];
|
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;
|
const name = is_pygmalion ? 'You' : name1;
|
||||||
if (!mesSendString.endsWith('\n')) {
|
if (!mesSendString.endsWith('\n')) {
|
||||||
mesSendString += '\n';
|
mesSendString += '\n';
|
||||||
@ -1961,7 +1984,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
mesSendString += name + ':';
|
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')) {
|
if (!mesSendString.endsWith('\n')) {
|
||||||
mesSendString += '\n';
|
mesSendString += '\n';
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,11 @@ import {
|
|||||||
reloadMarkdownProcessor,
|
reloadMarkdownProcessor,
|
||||||
reloadCurrentChat,
|
reloadCurrentChat,
|
||||||
getRequestHeaders,
|
getRequestHeaders,
|
||||||
|
substituteParams,
|
||||||
} from "../script.js";
|
} from "../script.js";
|
||||||
import {
|
import {
|
||||||
groups,
|
groups,
|
||||||
|
selected_group,
|
||||||
} from "./group-chats.js";
|
} from "./group-chats.js";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@ -109,6 +111,16 @@ let power_user = {
|
|||||||
allow_name2_display: false,
|
allow_name2_display: false,
|
||||||
hotswap_enabled: true,
|
hotswap_enabled: true,
|
||||||
timer_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 = [];
|
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);
|
$(`#character_sort_order option[data-order="${power_user.sort_order}"][data-field="${power_user.sort_field}"]`).prop("selected", true);
|
||||||
sortCharactersList();
|
sortCharactersList();
|
||||||
reloadMarkdownProcessor(power_user.render_formulas);
|
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);
|
const sortFunc = (a, b) => power_user.sort_order == 'asc' ? compareFunc(a, b) : compareFunc(b, a);
|
||||||
|
Reference in New Issue
Block a user