feature: customizable mappings for presets per model name / chat template (#4153) * feature: customizable mappings for presets per chat template This adds the ability to assign custom context/instruct presets on a per-chat-template(-hash) basis. Users using custom templates may use this feature to auto-enable the preset of their choice, rather than the built-in defaults. * fix: do not use chat tempate based instruct preset derivation if a preset was auto-selected already This fixes issues where regex matched presets are overridden. * reset chat template hash on connect * handle derive_mappings being null * unorthodox eslint requirement adherence * button styling * un-nest derivation related properties * Migrate setting * add bind model to preset button to the miscellaneous section * switch to unified button for model preset mappings * fix bind UI * eslint * do not include koboldcpp/ggml-model-xxx.gguf in preset saving * review fixes * stray console.log / eslint * Update checkbox state if no model map exists --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -4241,6 +4241,13 @@ | |||
| 4241 | </div> | 4241 | </div> |
| 4242 | <div> | 4242 | <div> |
| 4243 | <h4 class="standoutHeader" data-i18n="Miscellaneous">Miscellaneous</h4> | 4243 | <h4 class="standoutHeader" data-i18n="Miscellaneous">Miscellaneous</h4> |
| 4244 | <div name="bindModelPresetBlock"> | ||
| 4245 | <label for="bind_model_templates" class="checkbox_label"> | ||
| 4246 | <input id="bind_model_templates" type="checkbox" /> | ||
| 4247 | <small data-i18n="Bind Model to Templates">Bind Model to Templates</small> | ||
| 4248 | <span class="fa-solid fa-circle-question" data-i18n="[title]bind_model_templates_desc" title="When connecting to an API or choosing a model, automatically activate the current Instruct and Context templates if the model name or its chat template matches the currently loaded model."></span> | ||
| 4249 | </label> | ||
| 4250 | </div> | ||
| 4244 | <div> | 4251 | <div> |
| 4245 | <small> | 4252 | <small> |
| 4246 | <span data-i18n="Non-markdown strings"> | 4253 | <span data-i18n="Non-markdown strings"> |
| @@ -1315,16 +1315,19 @@ async function getStatusTextgen() { | |||
| 1315 | setOnlineStatus('no_connection'); | 1315 | setOnlineStatus('no_connection'); |
| 1316 | } | 1316 | } |
| 1317 | 1317 | ||
| 1318 | power_user.chat_template_hash = ''; | ||
| 1319 | |||
| 1318 | // Determine instruct mode preset | 1320 | // Determine instruct mode preset |
| 1319 | autoSelectInstructPreset(online_status); | 1321 | const autoSelected = autoSelectInstructPreset(online_status); |
| 1320 | 1322 | ||
| 1321 | const supportsTokenization = response.headers.get('x-supports-tokenization') === 'true'; | 1323 | const supportsTokenization = response.headers.get('x-supports-tokenization') === 'true'; |
| 1322 | supportsTokenization ? sessionStorage.setItem(TOKENIZER_SUPPORTED_KEY, 'true') : sessionStorage.removeItem(TOKENIZER_SUPPORTED_KEY); | 1324 | supportsTokenization ? sessionStorage.setItem(TOKENIZER_SUPPORTED_KEY, 'true') : sessionStorage.removeItem(TOKENIZER_SUPPORTED_KEY); |
| 1323 | 1325 | ||
| 1324 | const wantsInstructDerivation = (power_user.instruct.enabled && power_user.instruct.derived); | 1326 | const wantsInstructDerivation = !autoSelected && (power_user.instruct.enabled && power_user.instruct_derived); |
| 1325 | const wantsContextDerivation = power_user.context_derived; | 1327 | const wantsContextDerivation = !autoSelected && power_user.context_derived; |
| 1326 | const wantsContextSize = power_user.context_size_derived; | 1328 | const wantsContextSize = power_user.context_size_derived; |
| 1327 | const supportsChatTemplate = [textgen_types.KOBOLDCPP, textgen_types.LLAMACPP].includes(textgen_settings.type); | 1329 | const supportsChatTemplate = [textgen_types.KOBOLDCPP, textgen_types.LLAMACPP].includes(textgen_settings.type); |
| 1330 | |||
| 1328 | if (supportsChatTemplate && (wantsInstructDerivation || wantsContextDerivation || wantsContextSize)) { | 1331 | if (supportsChatTemplate && (wantsInstructDerivation || wantsContextDerivation || wantsContextSize)) { |
| 1329 | const response = await fetch('/api/backends/text-completions/props', { | 1332 | const response = await fetch('/api/backends/text-completions/props', { |
| 1330 | method: 'POST', | 1333 | method: 'POST', |
| @@ -1339,6 +1342,8 @@ async function getStatusTextgen() { | |||
| 1339 | const data = await response.json(); | 1342 | const data = await response.json(); |
| 1340 | if (data) { | 1343 | if (data) { |
| 1341 | const { chat_template, chat_template_hash } = data; | 1344 | const { chat_template, chat_template_hash } = data; |
| 1345 | power_user.chat_template_hash = chat_template_hash; | ||
| 1346 | |||
| 1342 | if (wantsContextSize && 'default_generation_settings' in data) { | 1347 | if (wantsContextSize && 'default_generation_settings' in data) { |
| 1343 | const backend_max_context = data['default_generation_settings']['n_ctx']; | 1348 | const backend_max_context = data['default_generation_settings']['n_ctx']; |
| 1344 | const old_value = max_context; | 1349 | const old_value = max_context; |
| @@ -1351,19 +1356,16 @@ async function getStatusTextgen() { | |||
| 1351 | } | 1356 | } |
| 1352 | } | 1357 | } |
| 1353 | console.log(`We have chat template ${chat_template.split('\n')[0]}...`); | 1358 | console.log(`We have chat template ${chat_template.split('\n')[0]}...`); |
| 1354 | const templates = await deriveTemplatesFromChatTemplate(chat_template, chat_template_hash); | 1359 | const { context, instruct } = await deriveTemplatesFromChatTemplate(chat_template, chat_template_hash); |
| 1355 | if (templates) { | 1360 | if (wantsContextDerivation && context) { |
| 1356 | const { context, instruct } = templates; | ||
| 1357 | if (wantsContextDerivation) { | ||
| 1358 | selectContextPreset(context, { isAuto: true }); | 1361 | selectContextPreset(context, { isAuto: true }); |
| 1359 | } | 1362 | } |
| 1360 | if (wantsInstructDerivation) { | 1363 | if (wantsInstructDerivation && power_user.instruct.enabled && instruct) { |
| 1361 | selectInstructPreset(instruct, { isAuto: true }); | 1364 | selectInstructPreset(instruct, { isAuto: true }); |
| 1362 | } | 1365 | } |
| 1363 | } | 1366 | } |
| 1364 | } | 1367 | } |
| 1365 | } | 1368 | } |
| 1366 | } | ||
| 1367 | 1369 | ||
| 1368 | // We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress. | 1370 | // We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress. |
| 1369 | if (online_status === 'no_connection' && data.response) { | 1371 | if (online_status === 'no_connection' && data.response) { |
| @@ -94,10 +94,12 @@ const parse_derivation = derivation => (typeof derivation === 'string') ? { | |||
| 94 | 'instruct': derivation, | 94 | 'instruct': derivation, |
| 95 | } : derivation; | 95 | } : derivation; |
| 96 | 96 | ||
| 97 | const not_found = { context: null, instruct: null }; | ||
| 98 | |||
| 97 | export async function deriveTemplatesFromChatTemplate(chat_template, hash) { | 99 | export async function deriveTemplatesFromChatTemplate(chat_template, hash) { |
| 98 | if (chat_template.trim() === '') { | 100 | if (chat_template.trim() === '') { |
| 99 | console.log('Missing chat template.'); | 101 | console.log('Missing chat template.'); |
| 100 | return null; | 102 | return not_found; |
| 101 | } | 103 | } |
| 102 | 104 | ||
| 103 | if (hash in hash_derivations) { | 105 | if (hash in hash_derivations) { |
| @@ -112,5 +114,65 @@ export async function deriveTemplatesFromChatTemplate(chat_template, hash) { | |||
| 112 | } | 114 | } |
| 113 | 115 | ||
| 114 | console.warn(`Unknown chat template hash: ${hash} for [${chat_template}]`); | 116 | console.warn(`Unknown chat template hash: ${hash} for [${chat_template}]`); |
| 115 | return null; | 117 | return not_found; |
| 118 | } | ||
| 119 | |||
| 120 | export async function bindModelTemplates(power_user, online_status) { | ||
| 121 | if (online_status === 'no_connection') { | ||
| 122 | return false; | ||
| 123 | } | ||
| 124 | |||
| 125 | const chat_template_hash = power_user.chat_template_hash; | ||
| 126 | |||
| 127 | const bind_model_templates = power_user.model_templates_mappings[online_status] | ||
| 128 | ?? power_user.model_templates_mappings[chat_template_hash] | ||
| 129 | ?? {}; | ||
| 130 | const bindings_match = bind_model_templates && power_user.context.preset == bind_model_templates['context'] && (!power_user.instruct.enabled || power_user.instruct.preset === bind_model_templates['instruct']); | ||
| 131 | |||
| 132 | |||
| 133 | const bound = []; | ||
| 134 | |||
| 135 | if (bindings_match) { | ||
| 136 | // unmap current preset | ||
| 137 | delete power_user.model_templates_mappings[chat_template_hash]; | ||
| 138 | delete power_user.model_templates_mappings[online_status]; | ||
| 139 | toastr.info(`Context preset for ${online_status} will use defaults when loaded the next time.`); | ||
| 140 | } else { | ||
| 141 | if (power_user.context_derived) { | ||
| 142 | if (power_user.context.preset !== bind_model_templates['context']) { | ||
| 143 | bound.push(`${power_user.context.preset} context preset`); | ||
| 144 | // toastr.info(`Bound ${power_user.context.preset} preset to currently loaded model and all models that share its chat template.`); | ||
| 145 | |||
| 146 | // map current preset to current chat template hash | ||
| 147 | bind_model_templates['context'] = power_user.context.preset; | ||
| 148 | } | ||
| 149 | } else { | ||
| 150 | toastr.warning('Note: Context derivation is disabled. Not including context preset.'); | ||
| 151 | } | ||
| 152 | if (power_user.instruct.enabled) { | ||
| 153 | if (power_user.instruct_derived) { | ||
| 154 | if (power_user.instruct.preset !== bind_model_templates['instruct']) { | ||
| 155 | bound.push(`${power_user.instruct.preset} instruct preset`); | ||
| 156 | |||
| 157 | bind_model_templates['instruct'] = power_user.instruct.preset; | ||
| 158 | } | ||
| 159 | } else { | ||
| 160 | toastr.warning('Note: Instruct derivation is disabled. Not including instruct preset.'); | ||
| 161 | } | ||
| 162 | } | ||
| 163 | if (bound.length == 0) { | ||
| 164 | toastr.warning('No applicable presets available.'); | ||
| 165 | return false; | ||
| 166 | } | ||
| 167 | |||
| 168 | toastr.info(`Bound ${online_status} to ${bound.join(', ')}.`); | ||
| 169 | if (!online_status.startsWith('koboldcpp/ggml-model-')) { | ||
| 170 | power_user.model_templates_mappings[online_status] = bind_model_templates; | ||
| 171 | } | ||
| 172 | if (chat_template_hash !== '') { | ||
| 173 | power_user.model_templates_mappings[chat_template_hash] = bind_model_templates; | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | return true; | ||
| 116 | } | 178 | } |
| @@ -1,6 +1,6 @@ | |||
| 1 | 'use strict'; | 1 | 'use strict'; |
| 2 | 2 | ||
| 3 | import { name1, name2, saveSettingsDebounced, substituteParams } from '../script.js'; | 3 | import { name1, name2, online_status, saveSettingsDebounced, substituteParams } from '../script.js'; |
| 4 | import { selected_group } from './group-chats.js'; | 4 | import { selected_group } from './group-chats.js'; |
| 5 | import { parseExampleIntoIndividual } from './openai.js'; | 5 | import { parseExampleIntoIndividual } from './openai.js'; |
| 6 | import { | 6 | import { |
| @@ -40,7 +40,6 @@ const controls = [ | |||
| 40 | { id: 'instruct_first_input_sequence', property: 'first_input_sequence', isCheckbox: false }, | 40 | { id: 'instruct_first_input_sequence', property: 'first_input_sequence', isCheckbox: false }, |
| 41 | { id: 'instruct_last_input_sequence', property: 'last_input_sequence', isCheckbox: false }, | 41 | { id: 'instruct_last_input_sequence', property: 'last_input_sequence', isCheckbox: false }, |
| 42 | { id: 'instruct_activation_regex', property: 'activation_regex', isCheckbox: false }, | 42 | { id: 'instruct_activation_regex', property: 'activation_regex', isCheckbox: false }, |
| 43 | { id: 'instruct_derived', property: 'derived', isCheckbox: true }, | ||
| 44 | { id: 'instruct_bind_to_context', property: 'bind_to_context', isCheckbox: true }, | 43 | { id: 'instruct_bind_to_context', property: 'bind_to_context', isCheckbox: true }, |
| 45 | { id: 'instruct_skip_examples', property: 'skip_examples', isCheckbox: true }, | 44 | { id: 'instruct_skip_examples', property: 'skip_examples', isCheckbox: true }, |
| 46 | { id: 'instruct_names_behavior', property: 'names_behavior', isCheckbox: false }, | 45 | { id: 'instruct_names_behavior', property: 'names_behavior', isCheckbox: false }, |
| @@ -102,7 +101,7 @@ export async function loadInstructMode(data) { | |||
| 102 | 101 | ||
| 103 | $('#instruct_enabled').parent().find('i').toggleClass('toggleEnabled', !!power_user.instruct.enabled); | 102 | $('#instruct_enabled').parent().find('i').toggleClass('toggleEnabled', !!power_user.instruct.enabled); |
| 104 | $('#instructSettingsBlock, #InstructSequencesColumn').toggleClass('disabled', !power_user.instruct.enabled); | 103 | $('#instructSettingsBlock, #InstructSequencesColumn').toggleClass('disabled', !power_user.instruct.enabled); |
| 105 | $('#instruct_derived').parent().find('i').toggleClass('toggleEnabled', !!power_user.instruct.derived); | 104 | $('#instruct_derived').parent().find('i').toggleClass('toggleEnabled', !!power_user.instruct_derived); |
| 106 | $('#instruct_bind_to_context').parent().find('i').toggleClass('toggleEnabled', !!power_user.instruct.bind_to_context); | 105 | $('#instruct_bind_to_context').parent().find('i').toggleClass('toggleEnabled', !!power_user.instruct.bind_to_context); |
| 107 | 106 | ||
| 108 | controls.forEach(control => { | 107 | controls.forEach(control => { |
| @@ -142,6 +141,19 @@ export async function loadInstructMode(data) { | |||
| 142 | } | 141 | } |
| 143 | 142 | ||
| 144 | /** | 143 | /** |
| 144 | * Updates the bind model template state based on the current model, instruct and context preset. | ||
| 145 | */ | ||
| 146 | export function updateBindModelTemplatesState() { | ||
| 147 | const bind_model_templates = power_user.model_templates_mappings[online_status] ?? power_user.model_templates_mappings[power_user.chat_template_hash]; | ||
| 148 | const bindings_match = (bind_model_templates && power_user.context.preset === bind_model_templates['context'] && (!power_user.instruct.enabled || power_user.instruct.preset === bind_model_templates['instruct'])) ?? false; | ||
| 149 | const current = $('#bind_model_templates').prop('checked'); | ||
| 150 | if (bindings_match === current) { | ||
| 151 | return; // No change needed | ||
| 152 | } | ||
| 153 | $('#bind_model_templates').prop('checked', bindings_match); | ||
| 154 | } | ||
| 155 | |||
| 156 | /** | ||
| 145 | * Select context template if not already selected. | 157 | * Select context template if not already selected. |
| 146 | * @param {string} preset Preset name. | 158 | * @param {string} preset Preset name. |
| 147 | * @param {object} [options={}] Optional arguments. | 159 | * @param {object} [options={}] Optional arguments. |
| @@ -161,6 +173,8 @@ export function selectContextPreset(preset, { quiet = false, isAuto = false } = | |||
| 161 | !quiet && toastr.info(`Context Template: "${preset}" ${isAuto ? 'auto-' : ''}selected`); | 173 | !quiet && toastr.info(`Context Template: "${preset}" ${isAuto ? 'auto-' : ''}selected`); |
| 162 | } | 174 | } |
| 163 | 175 | ||
| 176 | updateBindModelTemplatesState(); | ||
| 177 | |||
| 164 | saveSettingsDebounced(); | 178 | saveSettingsDebounced(); |
| 165 | } | 179 | } |
| 166 | 180 | ||
| @@ -191,6 +205,8 @@ export function selectInstructPreset(preset, { quiet = false, isAuto = false } = | |||
| 191 | !quiet && toastr.info('Instruct Mode enabled'); | 205 | !quiet && toastr.info('Instruct Mode enabled'); |
| 192 | } | 206 | } |
| 193 | 207 | ||
| 208 | updateBindModelTemplatesState(); | ||
| 209 | |||
| 194 | saveSettingsDebounced(); | 210 | saveSettingsDebounced(); |
| 195 | } | 211 | } |
| 196 | 212 | ||
| @@ -201,6 +217,21 @@ export function selectInstructPreset(preset, { quiet = false, isAuto = false } = | |||
| 201 | * @returns {boolean} True if instruct preset was activated by model id, false otherwise. | 217 | * @returns {boolean} True if instruct preset was activated by model id, false otherwise. |
| 202 | */ | 218 | */ |
| 203 | export function autoSelectInstructPreset(modelId) { | 219 | export function autoSelectInstructPreset(modelId) { |
| 220 | const model_templates_map = power_user.model_templates_mappings[modelId]; | ||
| 221 | |||
| 222 | if (model_templates_map) { | ||
| 223 | const { instruct, context } = model_templates_map; | ||
| 224 | if (instruct) { | ||
| 225 | selectInstructPreset(instruct, { isAuto: true }); | ||
| 226 | } | ||
| 227 | if (context) { | ||
| 228 | selectContextPreset(context, { isAuto: true }); | ||
| 229 | } | ||
| 230 | return true; | ||
| 231 | } else { | ||
| 232 | updateBindModelTemplatesState(); | ||
| 233 | } | ||
| 234 | |||
| 204 | // If instruct mode is disabled, don't do anything | 235 | // If instruct mode is disabled, don't do anything |
| 205 | if (!power_user.instruct.enabled) { | 236 | if (!power_user.instruct.enabled) { |
| 206 | return false; | 237 | return false; |
| @@ -747,7 +778,7 @@ jQuery(() => { | |||
| 747 | }); | 778 | }); |
| 748 | 779 | ||
| 749 | $('#instruct_derived').on('change', function () { | 780 | $('#instruct_derived').on('change', function () { |
| 750 | $('#instruct_derived').parent().find('i').toggleClass('toggleEnabled', !!power_user.instruct.derived); | 781 | $('#instruct_derived').parent().find('i').toggleClass('toggleEnabled', !!power_user.instruct_derived); |
| 751 | }); | 782 | }); |
| 752 | 783 | ||
| 753 | $('#instruct_bind_to_context').on('change', function () { | 784 | $('#instruct_bind_to_context').on('change', function () { |
| @@ -787,6 +818,8 @@ jQuery(() => { | |||
| 787 | // Select matching context template | 818 | // Select matching context template |
| 788 | selectMatchingContextTemplate(name); | 819 | selectMatchingContextTemplate(name); |
| 789 | } | 820 | } |
| 821 | |||
| 822 | updateBindModelTemplatesState(); | ||
| 790 | }); | 823 | }); |
| 791 | 824 | ||
| 792 | if (!CSS.supports('field-sizing', 'content')) { | 825 | if (!CSS.supports('field-sizing', 'content')) { |
| @@ -25,6 +25,7 @@ import { | |||
| 25 | setActiveCharacter, | 25 | setActiveCharacter, |
| 26 | entitiesFilter, | 26 | entitiesFilter, |
| 27 | doNewChat, | 27 | doNewChat, |
| 28 | online_status, | ||
| 28 | messageFormatting, | 29 | messageFormatting, |
| 29 | } from '../script.js'; | 30 | } from '../script.js'; |
| 30 | import { isMobile, initMovingUI, favsToHotswap } from './RossAscends-mods.js'; | 31 | import { isMobile, initMovingUI, favsToHotswap } from './RossAscends-mods.js'; |
| @@ -37,6 +38,7 @@ import { | |||
| 37 | loadInstructMode, | 38 | loadInstructMode, |
| 38 | names_behavior_types, | 39 | names_behavior_types, |
| 39 | selectInstructPreset, | 40 | selectInstructPreset, |
| 41 | updateBindModelTemplatesState, | ||
| 40 | } from './instruct-mode.js'; | 42 | } from './instruct-mode.js'; |
| 41 | 43 | ||
| 42 | import { getTagsList, tag_import_setting, tag_map, tags } from './tags.js'; | 44 | import { getTagsList, tag_import_setting, tag_map, tags } from './tags.js'; |
| @@ -57,6 +59,7 @@ import { loadSystemPrompts } from './sysprompt.js'; | |||
| 57 | import { fuzzySearchCategories } from './filters.js'; | 59 | import { fuzzySearchCategories } from './filters.js'; |
| 58 | import { accountStorage } from './util/AccountStorage.js'; | 60 | import { accountStorage } from './util/AccountStorage.js'; |
| 59 | import { DEFAULT_REASONING_TEMPLATE, loadReasoningTemplates } from './reasoning.js'; | 61 | import { DEFAULT_REASONING_TEMPLATE, loadReasoningTemplates } from './reasoning.js'; |
| 62 | import { bindModelTemplates } from './chat-templates.js'; | ||
| 60 | 63 | ||
| 61 | export { | 64 | export { |
| 62 | loadPowerUserSettings, | 65 | loadPowerUserSettings, |
| @@ -243,7 +246,6 @@ let power_user = { | |||
| 243 | macro: true, | 246 | macro: true, |
| 244 | names_behavior: names_behavior_types.FORCE, | 247 | names_behavior: names_behavior_types.FORCE, |
| 245 | activation_regex: '', | 248 | activation_regex: '', |
| 246 | derived: false, | ||
| 247 | bind_to_context: false, | 249 | bind_to_context: false, |
| 248 | user_alignment_message: '', | 250 | user_alignment_message: '', |
| 249 | system_same_as_user: false, | 251 | system_same_as_user: false, |
| @@ -260,8 +262,12 @@ let power_user = { | |||
| 260 | names_as_stop_strings: true, | 262 | names_as_stop_strings: true, |
| 261 | }, | 263 | }, |
| 262 | 264 | ||
| 265 | chat_template_hash: '', /** the chat template hash of the currently loaded model, if any; used when deriving mappings */ | ||
| 266 | |||
| 267 | instruct_derived: false, | ||
| 263 | context_derived: false, | 268 | context_derived: false, |
| 264 | context_size_derived: false, | 269 | context_size_derived: false, |
| 270 | model_templates_mappings: {}, /** user defined model identifier / chat template hash to instruct/context template mappings */ | ||
| 265 | 271 | ||
| 266 | sysprompt: { | 272 | sysprompt: { |
| 267 | enabled: true, | 273 | enabled: true, |
| @@ -1567,6 +1573,13 @@ async function loadPowerUserSettings(settings, data) { | |||
| 1567 | delete power_user.import_card_tags; | 1573 | delete power_user.import_card_tags; |
| 1568 | } | 1574 | } |
| 1569 | 1575 | ||
| 1576 | if (power_user?.instruct?.derived === true) { | ||
| 1577 | power_user.instruct_derived = true; | ||
| 1578 | delete power_user.instruct.derived; | ||
| 1579 | } | ||
| 1580 | |||
| 1581 | power_user.chat_template_hash = ''; | ||
| 1582 | |||
| 1570 | $('#single_line').prop('checked', power_user.single_line); | 1583 | $('#single_line').prop('checked', power_user.single_line); |
| 1571 | $('#relaxed_api_urls').prop('checked', power_user.relaxed_api_urls); | 1584 | $('#relaxed_api_urls').prop('checked', power_user.relaxed_api_urls); |
| 1572 | $('#world_import_dialog').prop('checked', power_user.world_import_dialog); | 1585 | $('#world_import_dialog').prop('checked', power_user.world_import_dialog); |
| @@ -1592,6 +1605,7 @@ async function loadPowerUserSettings(settings, data) { | |||
| 1592 | $('#encode_tags').prop('checked', power_user.encode_tags); | 1605 | $('#encode_tags').prop('checked', power_user.encode_tags); |
| 1593 | $('#example_messages_behavior').val(getExampleMessagesBehavior()); | 1606 | $('#example_messages_behavior').val(getExampleMessagesBehavior()); |
| 1594 | $(`#example_messages_behavior option[value="${getExampleMessagesBehavior()}"]`).prop('selected', true); | 1607 | $(`#example_messages_behavior option[value="${getExampleMessagesBehavior()}"]`).prop('selected', true); |
| 1608 | $('#instruct_derived').parent().find('i').toggleClass('toggleEnabled', !!power_user.instruct_derived); | ||
| 1595 | $('#context_derived').parent().find('i').toggleClass('toggleEnabled', !!power_user.context_derived); | 1609 | $('#context_derived').parent().find('i').toggleClass('toggleEnabled', !!power_user.context_derived); |
| 1596 | $('#context_size_derived').prop('checked', !!power_user.context_size_derived); | 1610 | $('#context_size_derived').prop('checked', !!power_user.context_size_derived); |
| 1597 | 1611 | ||
| @@ -1910,6 +1924,7 @@ async function loadContextSettings() { | |||
| 1910 | } | 1924 | } |
| 1911 | 1925 | ||
| 1912 | power_user.context.preset = name; | 1926 | power_user.context.preset = name; |
| 1927 | |||
| 1913 | contextControls.forEach(control => { | 1928 | contextControls.forEach(control => { |
| 1914 | const presetValue = preset[control.property] ?? control.defaultValue; | 1929 | const presetValue = preset[control.property] ?? control.defaultValue; |
| 1915 | 1930 | ||
| @@ -1944,6 +1959,8 @@ async function loadContextSettings() { | |||
| 1944 | } | 1959 | } |
| 1945 | } | 1960 | } |
| 1946 | 1961 | ||
| 1962 | updateBindModelTemplatesState(); | ||
| 1963 | |||
| 1947 | saveSettingsDebounced(); | 1964 | saveSettingsDebounced(); |
| 1948 | }); | 1965 | }); |
| 1949 | } | 1966 | } |
| @@ -3246,6 +3263,16 @@ $(document).ready(() => { | |||
| 3246 | $('#context_derived').parent().find('i').toggleClass('toggleEnabled', !!power_user.context_derived); | 3263 | $('#context_derived').parent().find('i').toggleClass('toggleEnabled', !!power_user.context_derived); |
| 3247 | }); | 3264 | }); |
| 3248 | 3265 | ||
| 3266 | $('#instruct_derived').on('input', function () { | ||
| 3267 | const value = !!$(this).prop('checked'); | ||
| 3268 | power_user.instruct_derived = value; | ||
| 3269 | saveSettingsDebounced(); | ||
| 3270 | }); | ||
| 3271 | |||
| 3272 | $('#instruct_derived').on('change', function () { | ||
| 3273 | $('#instruct_derived').parent().find('i').toggleClass('toggleEnabled', !!power_user.instruct_derived); | ||
| 3274 | }); | ||
| 3275 | |||
| 3249 | $('#context_size_derived').on('input', function () { | 3276 | $('#context_size_derived').on('input', function () { |
| 3250 | const value = !!$(this).prop('checked'); | 3277 | const value = !!$(this).prop('checked'); |
| 3251 | power_user.context_size_derived = value; | 3278 | power_user.context_size_derived = value; |
| @@ -3256,6 +3283,14 @@ $(document).ready(() => { | |||
| 3256 | $('#context_size_derived').prop('checked', !!power_user.context_size_derived); | 3283 | $('#context_size_derived').prop('checked', !!power_user.context_size_derived); |
| 3257 | }); | 3284 | }); |
| 3258 | 3285 | ||
| 3286 | $('#bind_model_templates').on('input', function () { | ||
| 3287 | if (bindModelTemplates(power_user, online_status)) { | ||
| 3288 | saveSettingsDebounced(); | ||
| 3289 | } | ||
| 3290 | }); | ||
| 3291 | |||
| 3292 | $('#bind_model_templates').on('change', updateBindModelTemplatesState); | ||
| 3293 | |||
| 3259 | $('#always-force-name2-checkbox').change(function () { | 3294 | $('#always-force-name2-checkbox').change(function () { |
| 3260 | power_user.always_force_name2 = !!$(this).prop('checked'); | 3295 | power_user.always_force_name2 = !!$(this).prop('checked'); |
| 3261 | saveSettingsDebounced(); | 3296 | saveSettingsDebounced(); |