Feat/Link sampler selection lock to TC API Type (#4782) * Update - Revert connection profile change TC commands load order This change was made to prevent preset tied samplers from breaking, such thing doesn't exist anymore. * Update - Unlink preset renaming logic from sampler selection lock * Update - Link TC sampler selection lock to API Type * Fix - Clean comments * Update - Use localforage selectedSamplers and data selectsampler as main sampler selection storage * Fix - ESLint errors * Update - Change lock tooltip with correct description * Fix - Move and await sampler select localforage initializer to finish Tried to move it to the most reasonable place possible that allowed to make an await. * Fix - Make loadTextGenSettings async to load API selected samplers

e8a75c33299b7f164c1af8f531de3a804060a374

Leandro Jofré <leandrotomasjofre@gmail.com>

Signed
6 files changed, +206 -384Ignore whitespace
public/script.js+1 -1
@@ -7395,7 +7395,7 @@ export async function getSettings() {
7395 loadNovelSettings(data, settings.nai_settings ?? settings);7395 loadNovelSettings(data, settings.nai_settings ?? settings);
73967396
7397 // TextGen7397 // TextGen
7398 loadTextGenSettings(data, settings);7398 await loadTextGenSettings(data, settings);
73997399
7400 // OpenAI7400 // OpenAI
7401 loadOpenAISettings(data, settings.oai_settings ?? settings);7401 loadOpenAISettings(data, settings.oai_settings ?? settings);
public/scripts/extensions/connection-manager/index.js+1 -1
@@ -47,8 +47,8 @@ const CC_COMMANDS = [
47];47];
4848
49const TC_COMMANDS = [49const TC_COMMANDS = [
50 'preset',
51 'api',50 'api',
51 'preset',
52 'api-url',52 'api-url',
53 'model',53 'model',
54 'sysprompt',54 'sysprompt',
public/scripts/preset-manager.js+0 -11
@@ -27,7 +27,6 @@ import { oai_settings, openai_setting_names, openai_settings } from './openai.js
27import { POPUP_RESULT, POPUP_TYPE, Popup } from './popup.js';27import { POPUP_RESULT, POPUP_TYPE, Popup } from './popup.js';
28import { context_presets, getContextSettings, power_user } from './power-user.js';28import { context_presets, getContextSettings, power_user } from './power-user.js';
29import { reasoning_templates } from './reasoning.js';29import { reasoning_templates } from './reasoning.js';
30import { getManualPresetSamplers, resetPresetSelectedSamplers, setPresetSamplersState } from './samplerSelect.js';
31import { SlashCommand } from './slash-commands/SlashCommand.js';30import { SlashCommand } from './slash-commands/SlashCommand.js';
32import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';31import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';
33import { enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';32import { enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
@@ -1072,16 +1071,6 @@ export async function initPresetManager() {
1072 return;1071 return;
1073 }1072 }
10741073
1075 if (apiId === 'textgenerationwebui') {
1076 const manualSamplersIterable = Object.entries(getManualPresetSamplers(oldName));
1077
1078 for (const [sampler, value] of manualSamplersIterable) {
1079 setPresetSamplersState(sampler, value, newName);
1080 }
1081
1082 await resetPresetSelectedSamplers(oldName, true);
1083 }
1084
1085 const successToast = !presetManager.isAdvancedFormatting() ? t`Preset renamed` : t`Template renamed`;1074 const successToast = !presetManager.isAdvancedFormatting() ? t`Preset renamed` : t`Template renamed`;
1086 toastr.success(successToast);1075 toastr.success(successToast);
1087 });1076 });
public/scripts/samplerSelect.js+190 -352
@@ -2,7 +2,6 @@ import {
2 main_api,2 main_api,
3 saveSettingsDebounced,3 saveSettingsDebounced,
4} from '../script.js';4} from '../script.js';
5import { power_user } from './power-user.js';
6//import { BIAS_CACHE, displayLogitBias, getLogitBiasListResult } from './logit-bias.js';5//import { BIAS_CACHE, displayLogitBias, getLogitBiasListResult } from './logit-bias.js';
7//import { getEventSourceStream } from './sse-stream.js';6//import { getEventSourceStream } from './sse-stream.js';
8//import { getSortableDelay, onlyUnique } from './utils.js';7//import { getSortableDelay, onlyUnique } from './utils.js';
@@ -14,8 +13,11 @@ import { localforage } from '../lib.js';
1413
15const forcedOnColoring = 'color: #89db35;';14const forcedOnColoring = 'color: #89db35;';
16const forcedOffColoring = 'color: #e84f62;';15const forcedOffColoring = 'color: #e84f62;';
1716const SELECT_SAMPLER = {
18let userDisabledSamplers, userShownSamplers;17 DATA: 'selectsampler',
18 SHOWN: 'shown',
19 HIDDEN: 'hidden',
20};
1921
20const textGenObjectStore = localforage.createInstance({ name: 'SillyTavern_TextCompletions' });22const textGenObjectStore = localforage.createInstance({ name: 'SillyTavern_TextCompletions' });
21let selectedSamplers = {};23let selectedSamplers = {};
@@ -38,28 +40,15 @@ async function showSamplerSelectPopup() {
3840
39 $('#resetSelectedSamplers').off('click').on('click', async function () {41 $('#resetSelectedSamplers').off('click').on('click', async function () {
40 console.log('saw sampler select reset click');42 console.log('saw sampler select reset click');
41 userDisabledSamplers = [];
42 userShownSamplers = [];
43 power_user.selectSamplers.forceShown = [];
44 power_user.selectSamplers.forceHidden = [];
4543
46 if (main_api === 'textgenerationwebui') {44 if (main_api === 'textgenerationwebui') {
47 $('#prioritizeManuallySelectedSamplers').toggleClass('toggleEnabled', false);45 $('#prioritizeManuallySelectedSamplers').toggleClass('toggleEnabled', false);
48 await resetPresetSelectedSamplers(null, true);46 await resetApiSelectedSamplers(null, true);
49 }47 }
5048
51 await validateDisabledSamplers(true);49 await validateDisabledSamplers(true);
52 });50 });
5351
54 $('#textgen_type').on('change', async function () {
55 console.log('changed TG Type, resetting custom samplers'); //unfortunate, but necessary unless we save custom samplers for each TGTytpe
56 userDisabledSamplers = [];
57 userShownSamplers = [];
58 power_user.selectSamplers.forceShown = [];
59 power_user.selectSamplers.forceHidden = [];
60 await validateDisabledSamplers();
61 });
62
63 if (main_api === 'textgenerationwebui') {52 if (main_api === 'textgenerationwebui') {
64 $('#prioritizeManuallySelectedSamplers').show();53 $('#prioritizeManuallySelectedSamplers').show();
65 $('#prioritizeManuallySelectedSamplers').toggleClass('toggleEnabled', isSamplerManualPriorityEnabled());54 $('#prioritizeManuallySelectedSamplers').toggleClass('toggleEnabled', isSamplerManualPriorityEnabled());
@@ -76,138 +65,143 @@ async function showSamplerSelectPopup() {
76 }65 }
7766
78 await showPromise;67 await showPromise;
79 if (main_api === 'textgenerationwebui') await savePresetSelectedSamplers();68 if (main_api === 'textgenerationwebui') await saveApiSelectedSamplers();
80}69}
8170
82function setSamplerListListeners() {71function getRelatedDOMElement(samplerName) {
83 // Goal 2: hide unchecked samplers from DOM72 let relatedDOMElement = $(`#${samplerName}_${main_api}`).parent();
84 let listContainer = $('#apiSamplersList');73 let targetDisplayType = 'flex';
85 listContainer.find('input').off('change').on('change', async function () {74 let displayname;
8675
87 const samplerName = this.name.replace('_checkbox', '');76 if (samplerName === 'json_schema') {
88 let relatedDOMElement = $(`#${samplerName}_${main_api}`).parent();77 relatedDOMElement = $('#json_schema_block');
89 let targetDisplayType = 'flex';78 targetDisplayType = 'block';
79 displayname = 'JSON Schema Block';
80 }
9081
91 if (samplerName === 'json_schema') {82 if (samplerName === 'grammar_string') {
92 relatedDOMElement = $('#json_schema_block');83 relatedDOMElement = $('#grammar_block_ooba');
93 targetDisplayType = 'block';84 targetDisplayType = 'block';
94 }85 displayname = 'Grammar Block';
86 }
9587
96 if (samplerName === 'grammar_string') {88 if (samplerName === 'guidance_scale') {
97 relatedDOMElement = $('#grammar_block_ooba');89 relatedDOMElement = $('#cfg_block_ooba');
98 targetDisplayType = 'block';90 targetDisplayType = 'block';
99 }91 displayname = 'CFG Block';
92 }
10093
101 if (samplerName === 'guidance_scale') {94 if (samplerName === 'mirostat_mode') {
102 relatedDOMElement = $('#cfg_block_ooba');95 relatedDOMElement = $('#mirostat_block_ooba');
103 targetDisplayType = 'block';96 targetDisplayType = 'block';
104 }97 displayname = 'Mirostat Block';
98 }
10599
106 if (samplerName === 'mirostat_mode') {100 if (samplerName === 'dry_multiplier') {
107 relatedDOMElement = $('#mirostat_block_ooba');101 relatedDOMElement = $('#dryBlock');
108 targetDisplayType = 'block';102 targetDisplayType = 'block';
109 }103 displayname = 'DRY Rep Pen Block';
104 }
110105
111 if (samplerName === 'dry_multiplier') {106 if (samplerName === 'xtc_probability') {
112 relatedDOMElement = $('#dryBlock');107 relatedDOMElement = $('#xtc_block');
113 targetDisplayType = 'block';108 targetDisplayType = 'block';
114 }109 displayname = 'XTC Block';
110 }
115111
116 if (samplerName === 'xtc_probability') {112 if (samplerName === 'dynatemp') {
117 relatedDOMElement = $('#xtc_block');113 relatedDOMElement = $('#dynatemp_block_ooba');
118 targetDisplayType = 'block';114 targetDisplayType = 'block';
119 }115 displayname = 'DynaTemp Block';
116 }
120117
121 if (samplerName === 'dynatemp') {118 if (samplerName === 'banned_tokens') {
122 relatedDOMElement = $('#dynatemp_block_ooba');119 relatedDOMElement = $('#banned_tokens_block_ooba');
123 targetDisplayType = 'block';120 targetDisplayType = 'block';
124 }121 }
125122
126 if (samplerName === 'banned_tokens') {123 if (samplerName === 'sampler_order') { //this is for kcpp sampler order
127 relatedDOMElement = $('#banned_tokens_block_ooba');124 relatedDOMElement = $('#sampler_order_block_kcpp');
128 targetDisplayType = 'block';125 displayname = 'KCPP Sampler Order Block';
129 }126 }
130127
131 if (samplerName === 'sampler_order') { //this is for kcpp sampler order128 if (samplerName === 'samplers') { //this is for lcpp sampler order
132 relatedDOMElement = $('#sampler_order_block_kcpp');129 relatedDOMElement = $('#sampler_order_block_lcpp');
133 }130 displayname = 'LCPP Sampler Order Block';
131 }
134132
135 if (samplerName === 'samplers') { //this is for lcpp sampler order133 if (samplerName === 'sampler_priority') { //this is for ooba's sampler priority
136 relatedDOMElement = $('#sampler_order_block_lcpp');134 relatedDOMElement = $('#sampler_priority_block_ooba');
137 }135 displayname = 'Ooba Sampler Priority Block';
136 }
138137
139 if (samplerName === 'sampler_priority') { //this is for ooba's sampler priority138 if (samplerName === 'samplers_priorities') { //this is for aphrodite's sampler priority
140 relatedDOMElement = $('#sampler_priority_block_ooba');139 relatedDOMElement = $('#sampler_priority_block_aphrodite');
141 }140 displayname = 'Aphrodite Sampler Priority Block';
141 }
142142
143 if (samplerName === 'samplers_priorities') { //this is for aphrodite's sampler priority143 if (samplerName === 'penalty_alpha') { //contrastive search only has one sampler, does it need its own block?
144 relatedDOMElement = $('#sampler_priority_block_aphrodite');144 relatedDOMElement = $('#contrastiveSearchBlock');
145 }145 displayname = 'Contrast Search Block';
146 }
146147
147 if (samplerName === 'penalty_alpha') { //contrastive search only has one sampler, does it need its own block?148 if (samplerName === 'num_beams') { // num_beams is the killswitch for Beam Search
148 relatedDOMElement = $('#contrastiveSearchBlock');149 relatedDOMElement = $('#beamSearchBlock');
149 }150 targetDisplayType = 'block';
151 displayname = 'Beam Search Block';
152 }
150153
151 if (samplerName === 'num_beams') { // num_beams is the killswitch for Beam Search154 if (samplerName === 'smoothing_factor') { // num_beams is the killswitch for Beam Search
152 relatedDOMElement = $('#beamSearchBlock');155 relatedDOMElement = $('#smoothingBlock');
153 targetDisplayType = 'block';156 targetDisplayType = 'block';
154 }157 displayname = 'Smoothing Block';
158 }
155159
156 if (samplerName === 'smoothing_factor') { // num_beams is the killswitch for Beam Search160 return { relatedDOMElement, targetDisplayType, displayname };
157 relatedDOMElement = $('#smoothingBlock');161}
158 targetDisplayType = 'block';162
159 }163function setSamplerListListeners() {
164 // Goal 2: hide unchecked samplers from DOM
165 let listContainer = $('#apiSamplersList');
166 listContainer.find('input').off('change').on('change', async function () {
167 const samplerName = this.name.replace('_checkbox', '');
168 const { relatedDOMElement, targetDisplayType } = getRelatedDOMElement(samplerName);
160169
161 // Get the current state of the custom data attribute170 // Get the current state of the custom data attribute
162 const previousState = relatedDOMElement.data('selectsampler');171 const previousState = relatedDOMElement.data(SELECT_SAMPLER.DATA);
163172 const isChecked = $(this).prop('checked');
164 if ($(this).prop('checked') === false) {173 const popupInputLabel = $(this).parent().find('.sampler_name');
165 //console.log('saw clicking checkbox from on to off...');174
166 if (previousState === 'shown') {175 if (isChecked === false) {
167 console.log('saw previously custom shown sampler');176 if (previousState === SELECT_SAMPLER.SHOWN) {
168 //console.log('removing from custom force show list');177 console.log('saw previously custom shown sampler => new state:', isChecked, samplerName);
169 relatedDOMElement.removeData('selectsampler');178 relatedDOMElement.removeData(SELECT_SAMPLER.DATA);
170 $(this).parent().find('.sampler_name').removeAttr('style');179 popupInputLabel.removeAttr('style');
171 power_user?.selectSamplers?.forceShown.splice(power_user?.selectSamplers?.forceShown.indexOf(samplerName), 1);
172 console.log(power_user?.selectSamplers?.forceShown);
173 } else {180 } else {
174 console.log('saw previous untouched sampler');181 console.log('saw previous untouched sampler => new state:', isChecked, samplerName);
175 //console.log(`adding ${samplerName} to force hide list`);182 relatedDOMElement.data(SELECT_SAMPLER.DATA, SELECT_SAMPLER.HIDDEN);
176 relatedDOMElement.data('selectsampler', 'hidden');183 popupInputLabel.attr('style', forcedOffColoring);
177 console.log(relatedDOMElement.data('selectsampler'));
178 power_user.selectSamplers.forceHidden.push(samplerName);
179 $(this).parent().find('.sampler_name').attr('style', forcedOffColoring);
180 console.log(power_user.selectSamplers.forceHidden);
181 }184 }
182 } else { // going from unchecked to checked185 } else {
183 //console.log('saw clicking checkbox from off to on...');186 if (previousState === SELECT_SAMPLER.HIDDEN) {
184 if (previousState === 'hidden') {187 console.log('saw previously custom hidden sampler => new state:', isChecked, samplerName);
185 console.log('saw previously custom hidden sampler');188 relatedDOMElement.removeData(SELECT_SAMPLER.DATA);
186 //console.log('removing from custom force hide list');189 popupInputLabel.removeAttr('style');
187 relatedDOMElement.removeData('selectsampler');
188 $(this).parent().find('.sampler_name').removeAttr('style');
189 power_user?.selectSamplers?.forceHidden.splice(power_user?.selectSamplers?.forceHidden.indexOf(samplerName), 1);
190 console.log(power_user?.selectSamplers?.forceHidden);
191 } else {190 } else {
192 console.log('saw previous untouched sampler');191 console.log('saw previous untouched sampler => new state:', isChecked, samplerName);
193 //console.log(`adding ${samplerName} to force shown list`);192 relatedDOMElement.data(SELECT_SAMPLER.DATA, SELECT_SAMPLER.SHOWN);
194 relatedDOMElement.data('selectsampler', 'shown');193 popupInputLabel.attr('style', forcedOnColoring);
195 console.log(relatedDOMElement.data('selectsampler'));
196 power_user.selectSamplers.forceShown.push(samplerName);
197 $(this).parent().find('.sampler_name').attr('style', forcedOnColoring);
198 console.log(power_user.selectSamplers.forceShown);
199 }194 }
200 }195 }
196
201 await saveSettingsDebounced();197 await saveSettingsDebounced();
202198
203 const shouldDisplay = $(this).prop('checked') ? targetDisplayType : 'none';199 const shouldDisplay = isChecked ? targetDisplayType : 'none';
204 relatedDOMElement.css('display', shouldDisplay);200 relatedDOMElement.css('display', shouldDisplay);
205201
206 if (main_api === 'textgenerationwebui') {202 if (main_api === 'textgenerationwebui') setApiSamplersState(samplerName, shouldDisplay !== 'none');
207 setPresetSamplersState(samplerName, shouldDisplay !== 'none');
208 }
209203
210 console.log(samplerName, relatedDOMElement.data('selectsampler'), shouldDisplay);204 console.log(samplerName, relatedDOMElement.data(SELECT_SAMPLER.DATA), shouldDisplay);
211 });205 });
212206
213}207}
@@ -237,115 +231,42 @@ async function listSamplers(main_api, arrayOnly = false) {
237 return availableSamplers;231 return availableSamplers;
238 }232 }
239233
240 const samplersActivatedManually = (main_api === 'textgenerationwebui') ? getManualActivePresetSamplers() : [];234 const samplersActivatedManually = (main_api === 'textgenerationwebui') ? getActiveManualApiSamplers() : [];
241 const prioritizeManualSamplerSelect = (main_api === 'textgenerationwebui') ? isSamplerManualPriorityEnabled() : false;235 const prioritizeManualSamplerSelect = (main_api === 'textgenerationwebui') ? isSamplerManualPriorityEnabled() : false;
242236
243 const samplersListHTML = availableSamplers.reduce((html, sampler) => {237 const samplersListHTML = availableSamplers.reduce((html, sampler) => {
244 let customColor, displayname;238 let customColor;
245 let targetDOMelement = $(`#${sampler}_${main_api}`);239 let { relatedDOMElement, displayname } = getRelatedDOMElement(sampler);
246
247 if (sampler === 'sampler_order') { //this is for kcpp sampler order
248 targetDOMelement = $('#sampler_order_block_kcpp');
249 displayname = 'KCPP Sampler Order Block';
250 }
251
252 if (sampler === 'samplers') { //this is for lcpp sampler order
253 targetDOMelement = $('#sampler_order_block_lcpp');
254 displayname = 'LCPP Sampler Order Block';
255 }
256
257 if (sampler === 'sampler_priority') { //this is for ooba's sampler priority
258 targetDOMelement = $('#sampler_priority_block_ooba');
259 displayname = 'Ooba Sampler Priority Block';
260 }
261
262 if (sampler === 'samplers_priorities') { //this is for aphrodite's sampler priority
263 targetDOMelement = $('#sampler_priority_block_aphrodite');
264 displayname = 'Aphrodite Sampler Priority Block';
265 }
266
267 if (sampler === 'penalty_alpha') { //contrastive search only has one sampler, does it need its own block?
268 targetDOMelement = $('#contrastiveSearchBlock');
269 displayname = 'Contrast Search Block';
270 }
271
272 if (sampler === 'num_beams') { // num_beams is the killswitch for Beam Search
273 targetDOMelement = $('#beamSearchBlock');
274 displayname = 'Beam Search Block';
275 }
276
277 if (sampler === 'smoothing_factor') { // num_beams is the killswitch for Beam Search
278 targetDOMelement = $('#smoothingBlock');
279 displayname = 'Smoothing Block';
280 }
281
282 if (sampler === 'dry_multiplier') {
283 targetDOMelement = $('#dryBlock');
284 displayname = 'DRY Rep Pen Block';
285 }
286 if (sampler === 'xtc_probability') {
287 targetDOMelement = $('#xtc_block');
288 displayname = 'XTC Block';
289 }
290
291 if (sampler === 'dynatemp') {
292 targetDOMelement = $('#dynatemp_block_ooba');
293 displayname = 'DynaTemp Block';
294 }
295
296 if (sampler === 'json_schema') {
297 targetDOMelement = $('#json_schema_block');
298 displayname = 'JSON Schema Block';
299 }
300
301 if (sampler === 'grammar_string') {
302 targetDOMelement = $('#grammar_block_ooba');
303 displayname = 'Grammar Block';
304 }
305
306 if (sampler === 'guidance_scale') {
307 targetDOMelement = $('#cfg_block_ooba');
308 displayname = 'CFG Block';
309 }
310
311 if (sampler === 'mirostat_mode') {
312 targetDOMelement = $('#mirostat_block_ooba');
313 displayname = 'Mirostat Block';
314 }
315240
316 const isManuallyActivated = samplersActivatedManually.includes(sampler);241 const isManuallyActivated = samplersActivatedManually.includes(sampler);
317 const isInForceHiddenArray = userDisabledSamplers.includes(sampler);242 const displayModified = relatedDOMElement.data(SELECT_SAMPLER.DATA);
318 const isInForceShownArray = userShownSamplers.includes(sampler);243 const isInDefaultState = !displayModified;
319 let isVisibleInDOM = isElementVisibleInDOM(targetDOMelement[0]);
320 const isInDefaultState = () => {
321 if (isVisibleInDOM && isInForceShownArray) { return false; }
322 else if (!isVisibleInDOM && isInForceHiddenArray) { return false; }
323 else { return true; }
324 };
325244
326 const shouldBeChecked = () => {245 const shouldBeChecked = () => {
246 let finalState = isElementVisibleInDOM(relatedDOMElement[0]);
247
327 if (prioritizeManualSamplerSelect) {248 if (prioritizeManualSamplerSelect) {
328 return isManuallyActivated;249 finalState = isManuallyActivated;
329 }250 }
330 else if (isInForceHiddenArray) {251
331 customColor = forcedOffColoring;252 else if (!isInDefaultState) {
332 return false;253 finalState = displayModified === SELECT_SAMPLER.SHOWN;
333 }254 customColor = finalState ? forcedOnColoring : forcedOffColoring;
334 else if (isInForceShownArray) {
335 customColor = forcedOnColoring;
336 return true;
337 }255 }
338 else { return isVisibleInDOM; }256
257 return finalState;
339 };258 };
340 console.log(sampler, targetDOMelement.prop('id'), isInDefaultState(), isInForceShownArray, isInForceHiddenArray, shouldBeChecked());259
341 if (displayname === undefined) { displayname = sampler; }260 console.log(sampler, relatedDOMElement.prop('id'), isInDefaultState, shouldBeChecked());
342 if (main_api === 'textgenerationwebui') setPresetSamplersState(sampler, shouldBeChecked());261
262 if (displayname === undefined) displayname = sampler;
263 if (main_api === 'textgenerationwebui') setApiSamplersState(sampler, shouldBeChecked());
264
343 return html + `265 return html + `
344 <div class="sampler_view_list_item wide50p flex-container">266 <label class="sampler_view_list_item wide50p flex-container">
345 <input type="checkbox" name="${sampler}_checkbox" ${shouldBeChecked() ? 'checked' : ''}>267 <input type="checkbox" name="${sampler}_checkbox" ${shouldBeChecked() ? 'checked' : ''}>
346 <small class="sampler_name" style="${customColor}">${displayname}</small>268 <small class="sampler_name" style="${customColor}">${displayname}</small>
347 </div>269 </label>`;
348 `;
349 }, '');270 }, '');
350271
351 return samplersListHTML;272 return samplersListHTML;
@@ -361,109 +282,28 @@ export async function validateDisabledSamplers(redraw = false) {
361 return;282 return;
362 }283 }
363284
364 const samplersActivatedManually = (main_api === 'textgenerationwebui') ? getManualActivePresetSamplers() : [];285 const samplersActivatedManually = (main_api === 'textgenerationwebui') ? getActiveManualApiSamplers() : [];
365 const prioritizeManualSamplerSelect = (main_api === 'textgenerationwebui') ? isSamplerManualPriorityEnabled() : false;286 const prioritizeManualSamplerSelect = (main_api === 'textgenerationwebui') ? isSamplerManualPriorityEnabled() : false;
366287
367 for (const sampler of APISamplers) {288 for (const sampler of APISamplers) {
368 let relatedDOMElement = $(`#${sampler}_${main_api}`).parent();289 const { relatedDOMElement, targetDisplayType } = getRelatedDOMElement(sampler);
369 let targetDisplayType = 'flex';
370
371 if (sampler === 'json_schema') {
372 relatedDOMElement = $('#json_schema_block');
373 targetDisplayType = 'block';
374 }
375
376 if (sampler === 'grammar_string') {
377 relatedDOMElement = $('#grammar_block_ooba');
378 targetDisplayType = 'block';
379 }
380
381 if (sampler === 'guidance_scale') {
382 relatedDOMElement = $('#cfg_block_ooba');
383 targetDisplayType = 'block';
384 }
385
386 if (sampler === 'mirostat_mode') {
387 relatedDOMElement = $('#mirostat_block_ooba');
388 targetDisplayType = 'block';
389 }
390
391 if (sampler === 'dynatemp') {
392 relatedDOMElement = $('#dynatemp_block_ooba');
393 targetDisplayType = 'block';
394 }
395
396 if (sampler === 'banned_tokens') {
397 relatedDOMElement = $('#banned_tokens_block_ooba');
398 targetDisplayType = 'block';
399 }
400
401 if (sampler === 'sampler_order') { //this is for kcpp sampler order
402 relatedDOMElement = $('#sampler_order_block_kcpp');
403 }
404
405 if (sampler === 'samplers') { //this is for lcpp sampler order
406 relatedDOMElement = $('#sampler_order_block_lcpp');
407 }
408
409 if (sampler === 'sampler_priority') { //this is for ooba's sampler priority
410 relatedDOMElement = $('#sampler_priority_block_ooba');
411 }
412
413 if (sampler === 'samplers_priorities') { //this is for aphrodite's sampler priority
414 relatedDOMElement = $('#sampler_priority_block_aphrodite');
415 }
416
417 if (sampler === 'dry_multiplier') {
418 relatedDOMElement = $('#dryBlock');
419 targetDisplayType = 'block';
420 }
421
422 if (sampler === 'xtc_probability') {
423 relatedDOMElement = $('#xtc_block');
424 targetDisplayType = 'block';
425 }
426
427 if (sampler === 'penalty_alpha') { //contrastive search only has one sampler, does it need its own block?
428 relatedDOMElement = $('#contrastiveSearchBlock');
429 }
430
431 if (sampler === 'num_beams') { // num_beams is the killswitch for Beam Search
432 relatedDOMElement = $('#beamSearchBlock');
433 }
434
435 if (sampler === 'smoothing_factor') { // num_beams is the killswitch for Beam Search
436 relatedDOMElement = $('#smoothingBlock');
437 }
438
439
440 if (power_user?.selectSamplers?.forceHidden.includes(sampler)) {
441 //default handling for standard sliders
442 relatedDOMElement.data('selectsampler', 'hidden');
443 relatedDOMElement.css('display', 'none');
444 } else if (power_user?.selectSamplers?.forceShown.includes(sampler)) {
445 relatedDOMElement.data('selectsampler', 'shown');
446 relatedDOMElement.css('display', targetDisplayType);
447 } else {
448 if (relatedDOMElement.data('selectsampler') === 'hidden') {
449 relatedDOMElement.removeAttr('selectsampler');
450 relatedDOMElement.css('display', targetDisplayType);
451 }
452 if (relatedDOMElement.data('selectsampler') === 'shown') {
453 relatedDOMElement.removeAttr('selectsampler');
454 relatedDOMElement.css('display', 'none');
455 }
456 }
457290
458 if (prioritizeManualSamplerSelect) {291 if (prioritizeManualSamplerSelect) {
459 const isManuallyActivated = samplersActivatedManually.includes(sampler);292 const isManuallyActivated = samplersActivatedManually.includes(sampler);
460 relatedDOMElement.css('display', isManuallyActivated ? targetDisplayType : 'none');293 relatedDOMElement.css('display', isManuallyActivated ? targetDisplayType : 'none');
294 } else {
295 const selectSamplerData = relatedDOMElement.data(SELECT_SAMPLER.DATA);
296 relatedDOMElement.css('display', selectSamplerData === SELECT_SAMPLER.SHOWN ? targetDisplayType : 'none');
461 }297 }
298
299 relatedDOMElement.removeData(SELECT_SAMPLER.DATA);
462 }300 }
463301
464 if (redraw) {302 if (!prioritizeManualSamplerSelect && main_api === 'textgenerationwebui') {
465 if (main_api === 'textgenerationwebui') showTGSamplerControls();303 showTGSamplerControls();
304 }
466305
306 if (redraw) {
467 let samplersHTML = await listSamplers(main_api);307 let samplersHTML = await listSamplers(main_api);
468 $('#apiSamplersList').empty().append(samplersHTML.toString());308 $('#apiSamplersList').empty().append(samplersHTML.toString());
469 setSamplerListListeners();309 setSamplerListListeners();
@@ -474,8 +314,9 @@ export async function validateDisabledSamplers(redraw = false) {
474314
475/**315/**
476 * Initializes the configuration object for manually selected samplers.316 * Initializes the configuration object for manually selected samplers.
317 * @returns void
477 */318 */
478export async function loadPresetSelectedSamplers() {319export async function loadApiSelectedSamplers() {
479 try {320 try {
480 console.debug('Text Completions: loading selected samplers');321 console.debug('Text Completions: loading selected samplers');
481 selectedSamplers = await textGenObjectStore.getItem('selectedSamplers') || {};322 selectedSamplers = await textGenObjectStore.getItem('selectedSamplers') || {};
@@ -487,8 +328,9 @@ export async function loadPresetSelectedSamplers() {
487328
488/**329/**
489 * Synchronizes the local forage instance with the selected samplers configuration object.330 * Synchronizes the local forage instance with the selected samplers configuration object.
331 * @returns void
490 */332 */
491export async function savePresetSelectedSamplers() {333export async function saveApiSelectedSamplers() {
492 try {334 try {
493 console.debug('Text Completions: saving selected samplers');335 console.debug('Text Completions: saving selected samplers');
494 await textGenObjectStore.setItem('selectedSamplers', selectedSamplers);336 await textGenObjectStore.setItem('selectedSamplers', selectedSamplers);
@@ -499,18 +341,19 @@ export async function savePresetSelectedSamplers() {
499341
500/**342/**
501 * Resets the selected samplers configuration object from the local forage instance.343 * Resets the selected samplers configuration object from the local forage instance.
502 * @param {string?} presetName Name of the target preset - It picks the current active TC preset name by default344 * @param {string?} tcApiType Name of the target API Type - It picks the currently active TC API type name by default
503 * @param {boolean} silent Suppresses the toastr message confirming that the data was deleted.345 * @param {boolean} silent Suppresses the toastr message confirming that the data was deleted.
346 * @returns void
504 */347 */
505export async function resetPresetSelectedSamplers(presetName = '', silent = false) {348export async function resetApiSelectedSamplers(tcApiType = '', silent = false) {
506 try {349 try {
507 if (!textgenerationwebui_settings?.preset && !presetName) return;350 if (!textgenerationwebui_settings?.type && !tcApiType) return;
508 if (!presetName) presetName = textgenerationwebui_settings.preset;351 if (!tcApiType) tcApiType = textgenerationwebui_settings.type;
509 if (!selectedSamplers[presetName]) return;352 if (!selectedSamplers[tcApiType]) return;
510353
511 console.debug('Text Completions: resetting selected samplers');354 console.debug('Text Completions: resetting selected samplers');
512 delete selectedSamplers[presetName];355 delete selectedSamplers[tcApiType];
513 await savePresetSelectedSamplers();356 await saveApiSelectedSamplers();
514 if (!silent) toastr.success('Selected samplers cleared.');357 if (!silent) toastr.success('Selected samplers cleared.');
515 } catch (error) {358 } catch (error) {
516 console.log('Text Completions: unable to reset selected preset samplers', error);359 console.log('Text Completions: unable to reset selected preset samplers', error);
@@ -521,43 +364,43 @@ export async function resetPresetSelectedSamplers(presetName = '', silent = fals
521 * Saves the visibility state for selected samplers into the configuration object.364 * Saves the visibility state for selected samplers into the configuration object.
522 * @param {string} samplerName Target sampler key name365 * @param {string} samplerName Target sampler key name
523 * @param {string|boolean} state Visibility state of the target sampler366 * @param {string|boolean} state Visibility state of the target sampler
524 * @param {string?} presetName Name of the target preset - It picks the current active TC preset name by default367 * @param {string?} tcApiType Name of the target API Type - It picks the currently active TC API type name by default
525 * @returns void368 * @returns void
526 */369 */
527export function setPresetSamplersState(samplerName, state, presetName = '') {370export function setApiSamplersState(samplerName, state, tcApiType = '') {
528 if (!textgenerationwebui_settings?.preset && !presetName) return;371 if (!textgenerationwebui_settings?.type && !tcApiType) return;
529 if (!presetName) presetName = textgenerationwebui_settings.preset;372 if (!tcApiType) tcApiType = textgenerationwebui_settings.type;
530 if (!selectedSamplers[presetName]) selectedSamplers[presetName] = {};373 if (!selectedSamplers[tcApiType]) selectedSamplers[tcApiType] = {};
531374
532 const presetSamplers = selectedSamplers[presetName];375 const presetSamplers = selectedSamplers[tcApiType];
533 presetSamplers[samplerName] = String(state) === 'true';376 presetSamplers[samplerName] = String(state) === 'true';
534}377}
535378
536/**379/**
537 * Returns the local forage object belonging to the active/selected TC preset380 * Returns the local forage object belonging to the active/selected TC API Type
538 * @param {string?} presetName Name of the target preset - It picks the current active TC preset name by default381 * @param {string?} tcApiType Name of the target API Type - It picks the currently active TC API type name by default
539 * @returns {object} Full localforage object with manual selections382 * @returns {object} Full localforage object with manual selections
540 */383 */
541export function getManualPresetSamplers(presetName = '') {384export function getAllManualApiSamplers(tcApiType = '') {
542 if (!textgenerationwebui_settings?.preset && !presetName) return {};385 if (!textgenerationwebui_settings?.type && !tcApiType) return {};
543 if (!presetName) presetName = textgenerationwebui_settings.preset;386 if (!tcApiType) tcApiType = textgenerationwebui_settings.type;
544 if (!selectedSamplers[presetName]) selectedSamplers[presetName] = {};387 if (!selectedSamplers[tcApiType]) selectedSamplers[tcApiType] = {};
545388
546 return selectedSamplers[presetName];389 return selectedSamplers[tcApiType];
547}390}
548391
549/**392/**
550 * Returns the key names of all the preset samplers activated manually.393 * Returns the key names of all the manually activated API Type samplers.
551 * @param {string?} presetName Name of the target preset - It picks the current active TC preset name by default394 * @param {string?} tcApiType Name of the target API Type - It picks the currently active TC API type name by default
552 * @returns {string[]} Array of sampler key names395 * @returns {string[]} Array of sampler key names
553 */396 */
554export function getManualActivePresetSamplers(presetName = '') {397export function getActiveManualApiSamplers(tcApiType = '') {
555 if (!textgenerationwebui_settings?.preset && !presetName) return [];398 if (!textgenerationwebui_settings?.type && !tcApiType) return [];
556 if (!presetName) presetName = textgenerationwebui_settings.preset;399 if (!tcApiType) tcApiType = textgenerationwebui_settings.type;
557 if (!selectedSamplers[presetName]) selectedSamplers[presetName] = {};400 if (!selectedSamplers[tcApiType]) selectedSamplers[tcApiType] = {};
558401
559 try {402 try {
560 const presetSamplers = Object.entries(selectedSamplers[presetName]);403 const presetSamplers = Object.entries(selectedSamplers[tcApiType]);
561404
562 return presetSamplers405 return presetSamplers
563 .filter(([key, val]) => val === true && key !== 'st_manual_priority')406 .filter(([key, val]) => val === true && key !== 'st_manual_priority')
@@ -570,36 +413,31 @@ export function getManualActivePresetSamplers(presetName = '') {
570413
571/**414/**
572 * @param {string|boolean} state Target state of the feature415 * @param {string|boolean} state Target state of the feature
573 * @param {string?} presetName Name of the target preset - It picks the current active TC preset name by default416 * @param {string?} tcApiType Name of the target API Type - It picks the currently active TC API type name by default
574 * @returns void417 * @returns void
575 */418 */
576export function toggleSamplerManualPriority(state = false, presetName = '') {419export function toggleSamplerManualPriority(state = false, tcApiType = '') {
577 if (!textgenerationwebui_settings?.preset && !presetName) return;420 if (!textgenerationwebui_settings?.type && !tcApiType) return;
578 if (!presetName) presetName = textgenerationwebui_settings.preset;421 if (!tcApiType) tcApiType = textgenerationwebui_settings.type;
579 if (!selectedSamplers[presetName]) selectedSamplers[presetName] = {};422 if (!selectedSamplers[tcApiType]) selectedSamplers[tcApiType] = {};
580423
581 const presetSamplers = selectedSamplers[presetName];424 const presetSamplers = selectedSamplers[tcApiType];
582 presetSamplers.st_manual_priority = String(state) === 'true';425 presetSamplers.st_manual_priority = String(state) === 'true';
583}426}
584427
585/**428/**
586 * @param {string?} presetName Name of the target preset - It picks the current active TC preset name by default429 * @param {string?} tcApiType Name of the target API Type - It picks the currently active TC API type name by default
587 * @returns {boolean}430 * @returns {boolean}
588 */431 */
589export function isSamplerManualPriorityEnabled(presetName = '') {432export function isSamplerManualPriorityEnabled(tcApiType = '') {
590 if (!textgenerationwebui_settings?.preset && !presetName) return false;433 if (!textgenerationwebui_settings?.type && !tcApiType) return false;
591 if (!presetName) presetName = textgenerationwebui_settings.preset;434 if (!tcApiType) tcApiType = textgenerationwebui_settings.type;
592 if (!selectedSamplers[presetName]) selectedSamplers[presetName] = {};435 if (!selectedSamplers[tcApiType]) selectedSamplers[tcApiType] = {};
593436
594 return selectedSamplers[presetName]?.st_manual_priority ?? false;437 return selectedSamplers[tcApiType]?.st_manual_priority ?? false;
595}438}
596439
597export async function initCustomSelectedSamplers() {440export async function initCustomSelectedSamplers() {
598 userDisabledSamplers = power_user?.selectSamplers?.forceHidden || [];
599 userShownSamplers = power_user?.selectSamplers?.forceShown || [];
600 power_user.selectSamplers = {};
601 power_user.selectSamplers.forceHidden = userDisabledSamplers;
602 power_user.selectSamplers.forceShown = userShownSamplers;
603 await saveSettingsDebounced();441 await saveSettingsDebounced();
604 $('#samplerSelectButton').off('click').on('click', showSamplerSelectPopup);442 $('#samplerSelectButton').off('click').on('click', showSamplerSelectPopup);
605}443}
public/scripts/templates/samplerSelector.html+1 -1
@@ -10,7 +10,7 @@
10 <i class="fa-solid fa-lock"></i>10 <i class="fa-solid fa-lock"></i>
11 <span data-i18n="Prioritize">Prioritize</span>11 <span data-i18n="Prioritize">Prioritize</span>
12 </div>12 </div>
13 <div class="margin5 fa-solid fa-exclamation-circle" data-i18n="[title]Toggle on to force the samplers selected in this menu to be shown when switching to this preset. By default, SillyTavern automatically selects samplers used or needed by the selected API Type in the API Connections panel." title="Toggle on to force the samplers selected in this menu to be shown when switching to this preset. By default, SillyTavern automatically selects samplers used or needed by the selected API Type in the API Connections panel."></div>13 <div class="margin5 fa-solid fa-exclamation-circle" data-i18n="[title]Toggle on to force the samplers selected in this menu to be shown when switching to the current API Type (API Connections Panel). By default, SillyTavern automatically selects samplers used or needed by the selected API Type." title="Toggle on to force the samplers selected in this menu to be shown when switching to the current API Type (API Connections Panel). By default, SillyTavern automatically selects samplers used or needed by the selected API Type."></div>
14 </div>14 </div>
15 <!--<div class="flex-container alignItemsBaseline">15 <!--<div class="flex-container alignItemsBaseline">
16 <div class="menu_button menu_button_icon" title="Create a new sampler">16 <div class="menu_button menu_button_icon" title="Create a new sampler">
public/scripts/textgen-settings.js+13 -18
@@ -20,7 +20,7 @@ import { autoSelectInstructPreset, selectContextPreset, selectInstructPreset } f
20import { BIAS_CACHE, createNewLogitBiasEntry, displayLogitBias, getLogitBiasListResult } from './logit-bias.js';20import { BIAS_CACHE, createNewLogitBiasEntry, displayLogitBias, getLogitBiasListResult } from './logit-bias.js';
2121
22import { power_user, registerDebugFunction } from './power-user.js';22import { power_user, registerDebugFunction } from './power-user.js';
23import { getManualActivePresetSamplers, isSamplerManualPriorityEnabled, loadPresetSelectedSamplers } from './samplerSelect.js';23import { getActiveManualApiSamplers, loadApiSelectedSamplers, isSamplerManualPriorityEnabled } from './samplerSelect.js';
24import { SECRET_KEYS, writeSecret } from './secrets.js';24import { SECRET_KEYS, writeSecret } from './secrets.js';
25import { getEventSourceStream } from './sse-stream.js';25import { getEventSourceStream } from './sse-stream.js';
26import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer, loadAphroditeModels, loadDreamGenModels, loadFeatherlessModels, loadGenericModels, loadInfermaticAIModels, loadMancerModels, loadOllamaModels, loadOpenRouterModels, loadTabbyModels, loadTogetherAIModels, loadVllmModels } from './textgen-models.js';26import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer, loadAphroditeModels, loadDreamGenModels, loadFeatherlessModels, loadGenericModels, loadInfermaticAIModels, loadMancerModels, loadOllamaModels, loadOpenRouterModels, loadTabbyModels, loadTogetherAIModels, loadVllmModels } from './textgen-models.js';
@@ -372,7 +372,6 @@ async function selectPreset(name) {
372 setSettingByName(name, value, true);372 setSettingByName(name, value, true);
373 }373 }
374 setGenerationParamsFromPreset(preset);374 setGenerationParamsFromPreset(preset);
375 showSamplerControls(null, true);
376 BIAS_CACHE.delete(BIAS_KEY);375 BIAS_CACHE.delete(BIAS_KEY);
377 displayLogitBias(preset.logit_bias, BIAS_KEY);376 displayLogitBias(preset.logit_bias, BIAS_KEY);
378 saveSettingsDebounced();377 saveSettingsDebounced();
@@ -530,7 +529,8 @@ function calculateLogitBias() {
530 return result;529 return result;
531}530}
532531
533export function loadTextGenSettings(data, loadedSettings) {532export async function loadTextGenSettings(data, loadedSettings) {
533 await loadApiSelectedSamplers();
534 textgenerationwebui_presets = convertPresets(data.textgenerationwebui_presets);534 textgenerationwebui_presets = convertPresets(data.textgenerationwebui_presets);
535 textgenerationwebui_preset_names = data.textgenerationwebui_preset_names ?? [];535 textgenerationwebui_preset_names = data.textgenerationwebui_preset_names ?? [];
536 Object.assign(settings, loadedSettings.textgenerationwebui_settings ?? {});536 Object.assign(settings, loadedSettings.textgenerationwebui_settings ?? {});
@@ -572,8 +572,7 @@ export function loadTextGenSettings(data, loadedSettings) {
572572
573 $('#textgen_type').val(settings.type);573 $('#textgen_type').val(settings.type);
574 $('#openrouter_providers_text').val(settings.openrouter_providers).trigger('change');574 $('#openrouter_providers_text').val(settings.openrouter_providers).trigger('change');
575 loadPresetSelectedSamplers();575 showSamplerControls(settings.type);
576 showSamplerControls();
577 BIAS_CACHE.delete(BIAS_KEY);576 BIAS_CACHE.delete(BIAS_KEY);
578 displayLogitBias(settings.logit_bias, BIAS_KEY);577 displayLogitBias(settings.logit_bias, BIAS_KEY);
579578
@@ -779,8 +778,6 @@ async function getStatusTextgen() {
779}778}
780779
781export function initTextGenSettings() {780export function initTextGenSettings() {
782 loadPresetSelectedSamplers();
783
784 $('#send_banned_tokens_textgenerationwebui').on('change', function () {781 $('#send_banned_tokens_textgenerationwebui').on('change', function () {
785 const checked = !!$(this).prop('checked');782 const checked = !!$(this).prop('checked');
786 toggleBannedStringsKillSwitch(checked,783 toggleBannedStringsKillSwitch(checked,
@@ -1078,21 +1075,19 @@ export function initTextGenSettings() {
1078/**1075/**
1079 * Hides and shows preset samplers from the left panel.1076 * Hides and shows preset samplers from the left panel.
1080 * @param {string?} apiType API Type selected in API Connections - Currently selected one by default1077 * @param {string?} apiType API Type selected in API Connections - Currently selected one by default
1081 * @param {boolean?} isPresetSwitch Wheter the trigger comes from a preset switch - false by default
1082 * @returns void1078 * @returns void
1083 */1079 */
1084function showSamplerControls(apiType = null, isPresetSwitch = false) {1080function showSamplerControls(apiType = null) {
1085 const prioritizeManualSamplerSelect = isSamplerManualPriorityEnabled();1081 $('#textgenerationwebui_api-settings [data-tg-samplers]').each(function(idx, elem) {
10861082 const typeSpecificControlled = $(elem).data('tg-type') !== undefined;
1087 if (isPresetSwitch && !prioritizeManualSamplerSelect) return;
10881083
1089 $('#textgenerationwebui_api-settings [data-tg-samplers]:not([data-tg-type])').each(function() {1084 if (!typeSpecificControlled) $(this).show();
1090 $(this).show();
1091 });1085 });
10921086
1093 showTypeSpecificControls(apiType ?? settings.type);1087 showTypeSpecificControls(apiType ?? settings.type);
10941088
1095 const samplersActivatedManually = getManualActivePresetSamplers();1089 const prioritizeManualSamplerSelect = isSamplerManualPriorityEnabled(apiType ?? settings.type);
1090 const samplersActivatedManually = getActiveManualApiSamplers(apiType ?? settings.type);
10961091
1097 if (!samplersActivatedManually?.length || !prioritizeManualSamplerSelect) return;1092 if (!samplersActivatedManually?.length || !prioritizeManualSamplerSelect) return;
10981093
@@ -1110,18 +1105,18 @@ function showSamplerControls(apiType = null, isPresetSwitch = false) {
1110 });1105 });
1111}1106}
11121107
1113function showTypeSpecificControls(type) {1108function showTypeSpecificControls(apiType) {
1114 $('[data-tg-type]').each(function () {1109 $('[data-tg-type]').each(function () {
1115 const mode = String($(this).attr('data-tg-type-mode') ?? '').toLowerCase().trim();1110 const mode = String($(this).attr('data-tg-type-mode') ?? '').toLowerCase().trim();
1116 const tgTypes = $(this).attr('data-tg-type').split(',').map(x => x.trim());1111 const tgTypes = $(this).attr('data-tg-type').split(',').map(x => x.trim());
11171112
1118 if (mode === 'except') {1113 if (mode === 'except') {
1119 $(this)[tgTypes.includes(type) ? 'hide' : 'show']();1114 $(this)[tgTypes.includes(apiType) ? 'hide' : 'show']();
1120 return;1115 return;
1121 }1116 }
11221117
1123 for (const tgType of tgTypes) {1118 for (const tgType of tgTypes) {
1124 if (tgType === type || tgType == 'all') {1119 if (tgType === apiType || tgType == 'all') {
1125 $(this).show();1120 $(this).show();
1126 return;1121 return;
1127 } else {1122 } else {