Add /preset command
This commit is contained in:
parent
2ca9015a5f
commit
9176f46caf
|
@ -177,7 +177,7 @@
|
||||||
<div>
|
<div>
|
||||||
<h4 class="margin0"><span data-i18n="openaipresets">Chat Completion Presets</span></h4>
|
<h4 class="margin0"><span data-i18n="openaipresets">Chat Completion Presets</span></h4>
|
||||||
<div class="flex-container flexNoGap">
|
<div class="flex-container flexNoGap">
|
||||||
<select id="settings_preset_openai" class="flex1 text_pole">
|
<select id="settings_preset_openai" class="flex1 text_pole" data-preset-manager-for="openai">
|
||||||
<option value="gui" data-i18n="default">Default</option>
|
<option value="gui" data-i18n="default">Default</option>
|
||||||
</select>
|
</select>
|
||||||
<div class="flex-container flexBasis100p justifyCenter">
|
<div class="flex-container flexBasis100p justifyCenter">
|
||||||
|
|
|
@ -192,6 +192,7 @@ import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay
|
||||||
import { loadMancerModels } from './scripts/mancer-settings.js';
|
import { loadMancerModels } from './scripts/mancer-settings.js';
|
||||||
import { appendFileContent, hasPendingFileAttachment, populateFileAttachment } from './scripts/chats.js';
|
import { appendFileContent, hasPendingFileAttachment, populateFileAttachment } from './scripts/chats.js';
|
||||||
import { replaceVariableMacros } from './scripts/variables.js';
|
import { replaceVariableMacros } from './scripts/variables.js';
|
||||||
|
import { initPresetManager } from './scripts/preset-manager.js';
|
||||||
|
|
||||||
//exporting functions and vars for mods
|
//exporting functions and vars for mods
|
||||||
export {
|
export {
|
||||||
|
@ -738,6 +739,7 @@ async function firstLoadInit() {
|
||||||
await getCharacters();
|
await getCharacters();
|
||||||
await getBackgrounds();
|
await getBackgrounds();
|
||||||
await initTokenizers();
|
await initTokenizers();
|
||||||
|
await initPresetManager();
|
||||||
initBackgrounds();
|
initBackgrounds();
|
||||||
initAuthorsNote();
|
initAuthorsNote();
|
||||||
initPersonas();
|
initPersonas();
|
||||||
|
@ -7446,7 +7448,10 @@ const swipe_right = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function connectAPISlash(_, text) {
|
/**
|
||||||
|
* @param {string} text API name
|
||||||
|
*/
|
||||||
|
async function connectAPISlash(_, text) {
|
||||||
if (!text) return;
|
if (!text) return;
|
||||||
|
|
||||||
const apiMap = {
|
const apiMap = {
|
||||||
|
@ -7460,7 +7465,29 @@ function connectAPISlash(_, text) {
|
||||||
button: '#api_button_novel',
|
button: '#api_button_novel',
|
||||||
},
|
},
|
||||||
'ooba': {
|
'ooba': {
|
||||||
|
selected: 'textgenerationwebui',
|
||||||
button: '#api_button_textgenerationwebui',
|
button: '#api_button_textgenerationwebui',
|
||||||
|
type: textgen_types.OOBA,
|
||||||
|
},
|
||||||
|
'tabby': {
|
||||||
|
selected: 'textgenerationwebui',
|
||||||
|
button: '#api_button_textgenerationwebui',
|
||||||
|
type: textgen_types.TABBY,
|
||||||
|
},
|
||||||
|
'mancer': {
|
||||||
|
selected: 'textgenerationwebui',
|
||||||
|
button: '#api_button_textgenerationwebui',
|
||||||
|
type: textgen_types.MANCER,
|
||||||
|
},
|
||||||
|
'aphrodite': {
|
||||||
|
selected: 'textgenerationwebui',
|
||||||
|
button: '#api_button_textgenerationwebui',
|
||||||
|
type: textgen_types.APHRODITE,
|
||||||
|
},
|
||||||
|
'kcpp': {
|
||||||
|
selected: 'textgenerationwebui',
|
||||||
|
button: '#api_button_textgenerationwebui',
|
||||||
|
type: textgen_types.KOBOLDCPP,
|
||||||
},
|
},
|
||||||
'oai': {
|
'oai': {
|
||||||
selected: 'openai',
|
selected: 'openai',
|
||||||
|
@ -7499,7 +7526,7 @@ function connectAPISlash(_, text) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const apiConfig = apiMap[text];
|
const apiConfig = apiMap[text.toLowerCase()];
|
||||||
if (!apiConfig) {
|
if (!apiConfig) {
|
||||||
toastr.error(`Error: ${text} is not a valid API`);
|
toastr.error(`Error: ${text} is not a valid API`);
|
||||||
return;
|
return;
|
||||||
|
@ -7513,11 +7540,23 @@ function connectAPISlash(_, text) {
|
||||||
$('#chat_completion_source').trigger('change');
|
$('#chat_completion_source').trigger('change');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (apiConfig.type) {
|
||||||
|
$(`#textgen_type option[value='${apiConfig.type}']`).prop('selected', true);
|
||||||
|
$('#textgen_type').trigger('change');
|
||||||
|
}
|
||||||
|
|
||||||
if (apiConfig.button) {
|
if (apiConfig.button) {
|
||||||
$(apiConfig.button).trigger('click');
|
$(apiConfig.button).trigger('click');
|
||||||
}
|
}
|
||||||
|
|
||||||
toastr.info(`API set to ${text}, trying to connect..`);
|
toastr.info(`API set to ${text}, trying to connect..`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await waitUntilCondition(() => online_status !== 'no_connection', 5000, 100);
|
||||||
|
console.log('Connection successful');
|
||||||
|
} catch {
|
||||||
|
console.log('Could not connect after 5 seconds, skipping.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function processDroppedFiles(files) {
|
export async function processDroppedFiles(files) {
|
||||||
|
@ -7771,7 +7810,7 @@ jQuery(async function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
registerSlashCommand('dupe', DupeChar, [], '– duplicates the currently selected character', true, true);
|
registerSlashCommand('dupe', DupeChar, [], '– duplicates the currently selected character', true, true);
|
||||||
registerSlashCommand('api', connectAPISlash, [], '<span class="monospace">(kobold, horde, novel, ooba, oai, claude, windowai, openrouter, scale, ai21, palm)</span> – connect to an API', true, true);
|
registerSlashCommand('api', connectAPISlash, [], '<span class="monospace">(kobold, horde, novel, ooba, tabby, mancer, aphrodite, kcpp, oai, claude, windowai, openrouter, scale, ai21, palm)</span> – connect to an API', true, true);
|
||||||
registerSlashCommand('impersonate', doImpersonate, ['imp'], '– calls an impersonation response', true, true);
|
registerSlashCommand('impersonate', doImpersonate, ['imp'], '– calls an impersonation response', true, true);
|
||||||
registerSlashCommand('delchat', doDeleteChat, [], '– deletes the current chat', true, true);
|
registerSlashCommand('delchat', doDeleteChat, [], '– deletes the current chat', true, true);
|
||||||
registerSlashCommand('closechat', doCloseChat, [], '– closes the current chat', true, true);
|
registerSlashCommand('closechat', doCloseChat, [], '– closes the current chat', true, true);
|
||||||
|
|
|
@ -2478,28 +2478,6 @@ function showWindowExtensionError() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function trySelectPresetByName(name) {
|
|
||||||
let preset_found = null;
|
|
||||||
for (const key in openai_setting_names) {
|
|
||||||
if (name.trim() == key.trim()) {
|
|
||||||
preset_found = key;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't change if the current preset is the same
|
|
||||||
if (preset_found && preset_found === oai_settings.preset_settings_openai) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preset_found) {
|
|
||||||
oai_settings.preset_settings_openai = preset_found;
|
|
||||||
const value = openai_setting_names[preset_found];
|
|
||||||
$(`#settings_preset_openai option[value="${value}"]`).attr('selected', true);
|
|
||||||
$('#settings_preset_openai').val(value).trigger('change');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Persist a settings preset with the given name
|
* Persist a settings preset with the given name
|
||||||
*
|
*
|
||||||
|
@ -3573,29 +3551,6 @@ $(document).ready(async function () {
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
// auto-select a preset based on character/group name
|
|
||||||
$(document).on('click', '.character_select', function () {
|
|
||||||
const chid = $(this).attr('chid');
|
|
||||||
const name = characters[chid]?.name;
|
|
||||||
|
|
||||||
if (!name) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
trySelectPresetByName(name);
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).on('click', '.group_select', function () {
|
|
||||||
const grid = $(this).data('id');
|
|
||||||
const name = groups.find(x => x.id === grid)?.name;
|
|
||||||
|
|
||||||
if (!name) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
trySelectPresetByName(name);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#update_oai_preset').on('click', async function () {
|
$('#update_oai_preset').on('click', async function () {
|
||||||
const name = oai_settings.preset_settings_openai;
|
const name = oai_settings.preset_settings_openai;
|
||||||
await saveOpenAIPreset(name, oai_settings);
|
await saveOpenAIPreset(name, oai_settings);
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
nai_settings,
|
nai_settings,
|
||||||
novelai_setting_names,
|
novelai_setting_names,
|
||||||
novelai_settings,
|
novelai_settings,
|
||||||
|
online_status,
|
||||||
saveSettingsDebounced,
|
saveSettingsDebounced,
|
||||||
this_chid,
|
this_chid,
|
||||||
} from '../script.js';
|
} from '../script.js';
|
||||||
|
@ -19,6 +20,7 @@ import { groups, selected_group } from './group-chats.js';
|
||||||
import { instruct_presets } from './instruct-mode.js';
|
import { instruct_presets } from './instruct-mode.js';
|
||||||
import { kai_settings } from './kai-settings.js';
|
import { kai_settings } from './kai-settings.js';
|
||||||
import { context_presets, getContextSettings, power_user } from './power-user.js';
|
import { context_presets, getContextSettings, power_user } from './power-user.js';
|
||||||
|
import { registerSlashCommand } from './slash-commands.js';
|
||||||
import {
|
import {
|
||||||
textgenerationwebui_preset_names,
|
textgenerationwebui_preset_names,
|
||||||
textgenerationwebui_presets,
|
textgenerationwebui_presets,
|
||||||
|
@ -28,6 +30,9 @@ import { download, parseJsonFile, waitUntilCondition } from './utils.js';
|
||||||
|
|
||||||
const presetManagers = {};
|
const presetManagers = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically select a preset for current API based on character or group name.
|
||||||
|
*/
|
||||||
function autoSelectPreset() {
|
function autoSelectPreset() {
|
||||||
const presetManager = getPresetManager();
|
const presetManager = getPresetManager();
|
||||||
|
|
||||||
|
@ -57,7 +62,12 @@ function autoSelectPreset() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPresetManager(apiId) {
|
/**
|
||||||
|
* Gets a preset manager by API id.
|
||||||
|
* @param {string} apiId API id
|
||||||
|
* @returns {PresetManager} Preset manager
|
||||||
|
*/
|
||||||
|
function getPresetManager(apiId = '') {
|
||||||
if (!apiId) {
|
if (!apiId) {
|
||||||
apiId = main_api == 'koboldhorde' ? 'kobold' : main_api;
|
apiId = main_api == 'koboldhorde' ? 'kobold' : main_api;
|
||||||
}
|
}
|
||||||
|
@ -69,6 +79,9 @@ function getPresetManager(apiId) {
|
||||||
return presetManagers[apiId];
|
return presetManagers[apiId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers preset managers for all select elements with data-preset-manager-for attribute.
|
||||||
|
*/
|
||||||
function registerPresetManagers() {
|
function registerPresetManagers() {
|
||||||
$('select[data-preset-manager-for]').each((_, e) => {
|
$('select[data-preset-manager-for]').each((_, e) => {
|
||||||
const forData = $(e).data('preset-manager-for');
|
const forData = $(e).data('preset-manager-for');
|
||||||
|
@ -85,21 +98,46 @@ class PresetManager {
|
||||||
this.apiId = apiId;
|
this.apiId = apiId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all preset names.
|
||||||
|
* @returns {string[]} List of preset names
|
||||||
|
*/
|
||||||
|
getAllPresets() {
|
||||||
|
return $(this.select).find('option').map((_, el) => el.text).toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a preset by name.
|
||||||
|
* @param {string} name Preset name
|
||||||
|
* @returns {any} Preset value
|
||||||
|
*/
|
||||||
findPreset(name) {
|
findPreset(name) {
|
||||||
return $(this.select).find(`option:contains(${name})`).val();
|
return $(this.select).find(`option:contains(${name})`).val();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the selected preset value.
|
||||||
|
* @returns {any} Selected preset value
|
||||||
|
*/
|
||||||
getSelectedPreset() {
|
getSelectedPreset() {
|
||||||
return $(this.select).find('option:selected').val();
|
return $(this.select).find('option:selected').val();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the selected preset name.
|
||||||
|
* @returns {string} Selected preset name
|
||||||
|
*/
|
||||||
getSelectedPresetName() {
|
getSelectedPresetName() {
|
||||||
return $(this.select).find('option:selected').text();
|
return $(this.select).find('option:selected').text();
|
||||||
}
|
}
|
||||||
|
|
||||||
selectPreset(preset) {
|
/**
|
||||||
$(this.select).find(`option[value=${preset}]`).prop('selected', true);
|
* Selects a preset by option value.
|
||||||
$(this.select).val(preset).trigger('change');
|
* @param {string} value Preset option value
|
||||||
|
*/
|
||||||
|
selectPreset(value) {
|
||||||
|
$(this.select).find(`option[value=${value}]`).prop('selected', true);
|
||||||
|
$(this.select).val(value).trigger('change');
|
||||||
}
|
}
|
||||||
|
|
||||||
async updatePreset() {
|
async updatePreset() {
|
||||||
|
@ -334,11 +372,91 @@ class PresetManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jQuery(async () => {
|
/**
|
||||||
await waitUntilCondition(() => eventSource !== undefined);
|
* Selects a preset by name for current API.
|
||||||
|
* @param {any} _ Named arguments
|
||||||
|
* @param {string} name Unnamed arguments
|
||||||
|
* @returns {Promise<string>} Selected or current preset name
|
||||||
|
*/
|
||||||
|
async function presetCommandCallback(_, name) {
|
||||||
|
const shouldReconnect = online_status !== 'no_connection';
|
||||||
|
const presetManager = getPresetManager();
|
||||||
|
const allPresets = presetManager.getAllPresets();
|
||||||
|
const currentPreset = presetManager.getSelectedPresetName();
|
||||||
|
|
||||||
|
if (!presetManager) {
|
||||||
|
console.debug(`Preset Manager not found for API: ${main_api}`);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
console.log('No name provided for /preset command, using current preset');
|
||||||
|
return currentPreset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(allPresets) || allPresets.length === 0) {
|
||||||
|
console.log(`No presets found for API: ${main_api}`);
|
||||||
|
return currentPreset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find exact match
|
||||||
|
const exactMatch = allPresets.find(p => p.toLowerCase().trim() === name.toLowerCase().trim());
|
||||||
|
|
||||||
|
if (exactMatch) {
|
||||||
|
console.log('Found exact preset match', exactMatch);
|
||||||
|
|
||||||
|
if (currentPreset !== exactMatch) {
|
||||||
|
const presetValue = presetManager.findPreset(exactMatch);
|
||||||
|
|
||||||
|
if (presetValue) {
|
||||||
|
presetManager.selectPreset(presetValue);
|
||||||
|
shouldReconnect && await waitForConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exactMatch;
|
||||||
|
} else {
|
||||||
|
// Find fuzzy match
|
||||||
|
const fuse = new Fuse(allPresets);
|
||||||
|
const fuzzyMatch = fuse.search(name);
|
||||||
|
|
||||||
|
if (!fuzzyMatch.length) {
|
||||||
|
console.warn(`WARN: Preset found with name ${name}`);
|
||||||
|
return currentPreset;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fuzzyPresetName = fuzzyMatch[0].item;
|
||||||
|
const fuzzyPresetValue = presetManager.findPreset(fuzzyPresetName);
|
||||||
|
|
||||||
|
if (fuzzyPresetValue) {
|
||||||
|
console.log('Found fuzzy preset match', fuzzyPresetName);
|
||||||
|
|
||||||
|
if (currentPreset !== fuzzyPresetName) {
|
||||||
|
presetManager.selectPreset(fuzzyPresetValue);
|
||||||
|
shouldReconnect && await waitForConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fuzzyPresetName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for API connection to be established.
|
||||||
|
*/
|
||||||
|
async function waitForConnection() {
|
||||||
|
try {
|
||||||
|
await waitUntilCondition(() => online_status !== 'no_connection', 5000, 100);
|
||||||
|
} catch {
|
||||||
|
console.log('Timeout waiting for API to connect');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function initPresetManager() {
|
||||||
eventSource.on(event_types.CHAT_CHANGED, autoSelectPreset);
|
eventSource.on(event_types.CHAT_CHANGED, autoSelectPreset);
|
||||||
registerPresetManagers();
|
registerPresetManagers();
|
||||||
|
registerSlashCommand('preset', presetCommandCallback, [], '<span class="monospace">(name)</span> – sets a preset by name for the current API', true, true);
|
||||||
|
|
||||||
$(document).on('click', '[data-preset-manager-update]', async function () {
|
$(document).on('click', '[data-preset-manager-update]', async function () {
|
||||||
const apiId = $(this).data('preset-manager-update');
|
const apiId = $(this).data('preset-manager-update');
|
||||||
const presetManager = getPresetManager(apiId);
|
const presetManager = getPresetManager(apiId);
|
||||||
|
@ -440,7 +558,7 @@ jQuery(async () => {
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('click', '[data-preset-manager-restore]', async function() {
|
$(document).on('click', '[data-preset-manager-restore]', async function () {
|
||||||
const apiId = $(this).data('preset-manager-restore');
|
const apiId = $(this).data('preset-manager-restore');
|
||||||
const presetManager = getPresetManager(apiId);
|
const presetManager = getPresetManager(apiId);
|
||||||
|
|
||||||
|
@ -490,4 +608,4 @@ jQuery(async () => {
|
||||||
toastr.success('Preset restored');
|
toastr.success('Preset restored');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
Loading…
Reference in New Issue