Merge branch 'staging' of https://github.com/SillyTavern/SillyTavern into staging
This commit is contained in:
commit
f19d6ac0ff
|
@ -60,6 +60,8 @@ module.exports = {
|
||||||
'no-trailing-spaces': 'error',
|
'no-trailing-spaces': 'error',
|
||||||
'object-curly-spacing': ['error', 'always'],
|
'object-curly-spacing': ['error', 'always'],
|
||||||
'space-infix-ops': 'error',
|
'space-infix-ops': 'error',
|
||||||
|
'no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }],
|
||||||
|
'no-cond-assign': 'error',
|
||||||
|
|
||||||
// These rules should eventually be enabled.
|
// These rules should eventually be enabled.
|
||||||
'no-async-promise-executor': 'off',
|
'no-async-promise-executor': 'off',
|
||||||
|
|
|
@ -3071,14 +3071,14 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
||||||
|
|
||||||
if (interruptedByCommand) {
|
if (interruptedByCommand) {
|
||||||
//$("#send_textarea").val('').trigger('input');
|
//$("#send_textarea").val('').trigger('input');
|
||||||
unblockGeneration();
|
unblockGeneration(type);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (main_api == 'kobold' && kai_settings.streaming_kobold && !kai_flags.can_use_streaming) {
|
if (main_api == 'kobold' && kai_settings.streaming_kobold && !kai_flags.can_use_streaming) {
|
||||||
toastr.error('Streaming is enabled, but the version of Kobold used does not support token streaming.', undefined, { timeOut: 10000, preventDuplicates: true });
|
toastr.error('Streaming is enabled, but the version of Kobold used does not support token streaming.', undefined, { timeOut: 10000, preventDuplicates: true });
|
||||||
unblockGeneration();
|
unblockGeneration(type);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3087,12 +3087,12 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
||||||
textgen_settings.legacy_api &&
|
textgen_settings.legacy_api &&
|
||||||
(textgen_settings.type === OOBA || textgen_settings.type === APHRODITE)) {
|
(textgen_settings.type === OOBA || textgen_settings.type === APHRODITE)) {
|
||||||
toastr.error('Streaming is not supported for the Legacy API. Update Ooba and use new API to enable streaming.', undefined, { timeOut: 10000, preventDuplicates: true });
|
toastr.error('Streaming is not supported for the Legacy API. Update Ooba and use new API to enable streaming.', undefined, { timeOut: 10000, preventDuplicates: true });
|
||||||
unblockGeneration();
|
unblockGeneration(type);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isHordeGenerationNotAllowed()) {
|
if (isHordeGenerationNotAllowed()) {
|
||||||
unblockGeneration();
|
unblockGeneration(type);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3128,7 +3128,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
||||||
setCharacterName('');
|
setCharacterName('');
|
||||||
} else {
|
} else {
|
||||||
console.log('No enabled members found');
|
console.log('No enabled members found');
|
||||||
unblockGeneration();
|
unblockGeneration(type);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3302,7 +3302,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
||||||
|
|
||||||
if (aborted) {
|
if (aborted) {
|
||||||
console.debug('Generation aborted by extension interceptors');
|
console.debug('Generation aborted by extension interceptors');
|
||||||
unblockGeneration();
|
unblockGeneration(type);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -3316,7 +3316,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
||||||
adjustedParams = await adjustHordeGenerationParams(max_context, amount_gen);
|
adjustedParams = await adjustHordeGenerationParams(max_context, amount_gen);
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
unblockGeneration();
|
unblockGeneration(type);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
if (horde_settings.auto_adjust_context_length) {
|
if (horde_settings.auto_adjust_context_length) {
|
||||||
|
@ -4103,7 +4103,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
||||||
await eventSource.emit(event_types.IMPERSONATE_READY, getMessage);
|
await eventSource.emit(event_types.IMPERSONATE_READY, getMessage);
|
||||||
}
|
}
|
||||||
else if (type == 'quiet') {
|
else if (type == 'quiet') {
|
||||||
unblockGeneration();
|
unblockGeneration(type);
|
||||||
return getMessage;
|
return getMessage;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -4171,7 +4171,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
||||||
|
|
||||||
console.debug('/api/chats/save called by /Generate');
|
console.debug('/api/chats/save called by /Generate');
|
||||||
await saveChatConditional();
|
await saveChatConditional();
|
||||||
unblockGeneration();
|
unblockGeneration(type);
|
||||||
streamingProcessor = null;
|
streamingProcessor = null;
|
||||||
|
|
||||||
if (type !== 'quiet') {
|
if (type !== 'quiet') {
|
||||||
|
@ -4189,7 +4189,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
||||||
|
|
||||||
generatedPromptCache = '';
|
generatedPromptCache = '';
|
||||||
|
|
||||||
unblockGeneration();
|
unblockGeneration(type);
|
||||||
console.log(exception);
|
console.log(exception);
|
||||||
streamingProcessor = null;
|
streamingProcessor = null;
|
||||||
throw exception;
|
throw exception;
|
||||||
|
@ -4259,7 +4259,16 @@ function flushWIDepthInjections() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function unblockGeneration() {
|
/**
|
||||||
|
* Unblocks the UI after a generation is complete.
|
||||||
|
* @param {string} [type] Generation type (optional)
|
||||||
|
*/
|
||||||
|
function unblockGeneration(type) {
|
||||||
|
// Don't unblock if a parallel stream is still running
|
||||||
|
if (type === 'quiet' && streamingProcessor && !streamingProcessor.isFinished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
is_send_press = false;
|
is_send_press = false;
|
||||||
activateSendButtons();
|
activateSendButtons();
|
||||||
showSwipeButtons();
|
showSwipeButtons();
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
import { callPopup, eventSource, event_types, getRequestHeaders, saveSettingsDebounced } from '../../../script.js';
|
import { callPopup, eventSource, event_types, generateQuietPrompt, getRequestHeaders, saveSettingsDebounced, substituteParams } from '../../../script.js';
|
||||||
import { dragElement, isMobile } from '../../RossAscends-mods.js';
|
import { dragElement, isMobile } from '../../RossAscends-mods.js';
|
||||||
import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js';
|
import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js';
|
||||||
import { loadMovingUIState, power_user } from '../../power-user.js';
|
import { loadMovingUIState, power_user } from '../../power-user.js';
|
||||||
import { registerSlashCommand } from '../../slash-commands.js';
|
import { registerSlashCommand } from '../../slash-commands.js';
|
||||||
import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence } from '../../utils.js';
|
import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence } from '../../utils.js';
|
||||||
import { hideMutedSprites } from '../../group-chats.js';
|
import { hideMutedSprites } from '../../group-chats.js';
|
||||||
|
import { isJsonSchemaSupported } from '../../textgen-settings.js';
|
||||||
export { MODULE_NAME };
|
export { MODULE_NAME };
|
||||||
|
|
||||||
const MODULE_NAME = 'expressions';
|
const MODULE_NAME = 'expressions';
|
||||||
const UPDATE_INTERVAL = 2000;
|
const UPDATE_INTERVAL = 2000;
|
||||||
const STREAMING_UPDATE_INTERVAL = 6000;
|
const STREAMING_UPDATE_INTERVAL = 10000;
|
||||||
const TALKINGCHECK_UPDATE_INTERVAL = 500;
|
const TALKINGCHECK_UPDATE_INTERVAL = 500;
|
||||||
const DEFAULT_FALLBACK_EXPRESSION = 'joy';
|
const DEFAULT_FALLBACK_EXPRESSION = 'joy';
|
||||||
|
const DEFAULT_LLM_PROMPT = 'Pause your roleplay. Classify the emotion of the last message. Output just one word, e.g. "joy" or "anger". Choose only one of the following labels: {{labels}}';
|
||||||
const DEFAULT_EXPRESSIONS = [
|
const DEFAULT_EXPRESSIONS = [
|
||||||
'talkinghead',
|
'talkinghead',
|
||||||
'admiration',
|
'admiration',
|
||||||
|
@ -43,6 +45,11 @@ const DEFAULT_EXPRESSIONS = [
|
||||||
'surprise',
|
'surprise',
|
||||||
'neutral',
|
'neutral',
|
||||||
];
|
];
|
||||||
|
const EXPRESSION_API = {
|
||||||
|
local: 0,
|
||||||
|
extras: 1,
|
||||||
|
llm: 2,
|
||||||
|
};
|
||||||
|
|
||||||
let expressionsList = null;
|
let expressionsList = null;
|
||||||
let lastCharacter = undefined;
|
let lastCharacter = undefined;
|
||||||
|
@ -55,7 +62,7 @@ let lastServerResponseTime = 0;
|
||||||
export let lastExpression = {};
|
export let lastExpression = {};
|
||||||
|
|
||||||
function isTalkingHeadEnabled() {
|
function isTalkingHeadEnabled() {
|
||||||
return extension_settings.expressions.talkinghead && !extension_settings.expressions.local;
|
return extension_settings.expressions.talkinghead && extension_settings.expressions.api == EXPRESSION_API.extras;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -585,10 +592,10 @@ function handleImageChange() {
|
||||||
async function moduleWorker() {
|
async function moduleWorker() {
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
|
|
||||||
// Hide and disable Talkinghead while in local mode
|
// Hide and disable Talkinghead while not in extras
|
||||||
$('#image_type_block').toggle(!extension_settings.expressions.local);
|
$('#image_type_block').toggle(extension_settings.expressions.api == EXPRESSION_API.extras);
|
||||||
|
|
||||||
if (extension_settings.expressions.local && extension_settings.expressions.talkinghead) {
|
if (extension_settings.expressions.api != EXPRESSION_API.extras && extension_settings.expressions.talkinghead) {
|
||||||
$('#image_type_toggle').prop('checked', false);
|
$('#image_type_toggle').prop('checked', false);
|
||||||
setTalkingHeadState(false);
|
setTalkingHeadState(false);
|
||||||
}
|
}
|
||||||
|
@ -628,7 +635,7 @@ async function moduleWorker() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const offlineMode = $('.expression_settings .offline_mode');
|
const offlineMode = $('.expression_settings .offline_mode');
|
||||||
if (!modules.includes('classify') && !extension_settings.expressions.local) {
|
if (!modules.includes('classify') && extension_settings.expressions.api == EXPRESSION_API.extras) {
|
||||||
$('#open_chat_expressions').show();
|
$('#open_chat_expressions').show();
|
||||||
$('#no_chat_expressions').hide();
|
$('#no_chat_expressions').hide();
|
||||||
offlineMode.css('display', 'block');
|
offlineMode.css('display', 'block');
|
||||||
|
@ -821,7 +828,7 @@ function setTalkingHeadState(newState) {
|
||||||
extension_settings.expressions.talkinghead = newState; // Store setting
|
extension_settings.expressions.talkinghead = newState; // Store setting
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
|
|
||||||
if (extension_settings.expressions.local) {
|
if (extension_settings.expressions.api == EXPRESSION_API.local || extension_settings.expressions.api == EXPRESSION_API.llm) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -900,7 +907,7 @@ async function classifyCommand(_, text) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!modules.includes('classify') && !extension_settings.expressions.local) {
|
if (!modules.includes('classify') && extension_settings.expressions.api == EXPRESSION_API.extras) {
|
||||||
toastr.warning('Text classification is disabled or not available');
|
toastr.warning('Text classification is disabled or not available');
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -971,9 +978,76 @@ function sampleClassifyText(text) {
|
||||||
return result.trim();
|
return result.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the classification prompt for the LLM API.
|
||||||
|
* @param {string[]} labels A list of labels to search for.
|
||||||
|
* @returns {Promise<string>} Prompt for the LLM API.
|
||||||
|
*/
|
||||||
|
async function getLlmPrompt(labels) {
|
||||||
|
if (isJsonSchemaSupported()) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const labelsString = labels.map(x => `"${x}"`).join(', ');
|
||||||
|
const prompt = substituteParams(String(extension_settings.expressions.llmPrompt))
|
||||||
|
.replace(/{{labels}}/gi, labelsString);
|
||||||
|
return prompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the emotion response from the LLM API.
|
||||||
|
* @param {string} emotionResponse The response from the LLM API.
|
||||||
|
* @param {string[]} labels A list of labels to search for.
|
||||||
|
* @returns {string} The parsed emotion or the fallback expression.
|
||||||
|
*/
|
||||||
|
function parseLlmResponse(emotionResponse, labels) {
|
||||||
|
const fallbackExpression = getFallbackExpression();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsedEmotion = JSON.parse(emotionResponse);
|
||||||
|
return parsedEmotion?.emotion ?? fallbackExpression;
|
||||||
|
} catch {
|
||||||
|
const fuse = new Fuse([emotionResponse]);
|
||||||
|
for (const label of labels) {
|
||||||
|
const result = fuse.search(label);
|
||||||
|
if (result.length > 0) {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Could not parse emotion response ' + emotionResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTextGenSettingsReady(args) {
|
||||||
|
// Only call if inside an API call
|
||||||
|
if (inApiCall && extension_settings.expressions.api === EXPRESSION_API.llm && isJsonSchemaSupported()) {
|
||||||
|
const emotions = DEFAULT_EXPRESSIONS.filter((e) => e != 'talkinghead');
|
||||||
|
Object.assign(args, {
|
||||||
|
top_k: 1,
|
||||||
|
stop: [],
|
||||||
|
stopping_strings: [],
|
||||||
|
custom_token_bans: [],
|
||||||
|
json_schema: {
|
||||||
|
$schema: 'http://json-schema.org/draft-04/schema#',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
emotion: {
|
||||||
|
type: 'string',
|
||||||
|
enum: emotions,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: [
|
||||||
|
'emotion',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function getExpressionLabel(text) {
|
async function getExpressionLabel(text) {
|
||||||
// Return if text is undefined, saving a costly fetch request
|
// Return if text is undefined, saving a costly fetch request
|
||||||
if ((!modules.includes('classify') && !extension_settings.expressions.local) || !text) {
|
if ((!modules.includes('classify') && extension_settings.expressions.api == EXPRESSION_API.extras) || !text) {
|
||||||
return getFallbackExpression();
|
return getFallbackExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -984,39 +1058,50 @@ async function getExpressionLabel(text) {
|
||||||
text = sampleClassifyText(text);
|
text = sampleClassifyText(text);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (extension_settings.expressions.local) {
|
switch (extension_settings.expressions.api) {
|
||||||
// Local transformers pipeline
|
// Local BERT pipeline
|
||||||
const apiResult = await fetch('/api/extra/classify', {
|
case EXPRESSION_API.local: {
|
||||||
method: 'POST',
|
const localResult = await fetch('/api/extra/classify', {
|
||||||
headers: getRequestHeaders(),
|
method: 'POST',
|
||||||
body: JSON.stringify({ text: text }),
|
headers: getRequestHeaders(),
|
||||||
});
|
body: JSON.stringify({ text: text }),
|
||||||
|
});
|
||||||
|
|
||||||
if (apiResult.ok) {
|
if (localResult.ok) {
|
||||||
const data = await apiResult.json();
|
const data = await localResult.json();
|
||||||
return data.classification[0].label;
|
return data.classification[0].label;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
// Using LLM
|
||||||
|
case EXPRESSION_API.llm: {
|
||||||
|
const expressionsList = await getExpressionsList();
|
||||||
|
const prompt = await getLlmPrompt(expressionsList);
|
||||||
|
const emotionResponse = await generateQuietPrompt(prompt, false, false);
|
||||||
|
return parseLlmResponse(emotionResponse, expressionsList);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Extras
|
// Extras
|
||||||
const url = new URL(getApiUrl());
|
default: {
|
||||||
url.pathname = '/api/classify';
|
const url = new URL(getApiUrl());
|
||||||
|
url.pathname = '/api/classify';
|
||||||
|
|
||||||
const apiResult = await doExtrasFetch(url, {
|
const extrasResult = await doExtrasFetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Bypass-Tunnel-Reminder': 'bypass',
|
'Bypass-Tunnel-Reminder': 'bypass',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ text: text }),
|
body: JSON.stringify({ text: text }),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (apiResult.ok) {
|
if (extrasResult.ok) {
|
||||||
const data = await apiResult.json();
|
const data = await extrasResult.json();
|
||||||
return data.classification[0].label;
|
return data.classification[0].label;
|
||||||
}
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
toastr.info('Could not classify expression. Check the console or your backend for more information.');
|
||||||
|
console.error(error);
|
||||||
return getFallbackExpression();
|
return getFallbackExpression();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1177,23 +1262,12 @@ async function getExpressionsList() {
|
||||||
*/
|
*/
|
||||||
async function resolveExpressionsList() {
|
async function resolveExpressionsList() {
|
||||||
// get something for offline mode (default images)
|
// get something for offline mode (default images)
|
||||||
if (!modules.includes('classify') && !extension_settings.expressions.local) {
|
if (!modules.includes('classify') && extension_settings.expressions.api == EXPRESSION_API.extras) {
|
||||||
return DEFAULT_EXPRESSIONS;
|
return DEFAULT_EXPRESSIONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (extension_settings.expressions.local) {
|
if (extension_settings.expressions.api == EXPRESSION_API.extras) {
|
||||||
const apiResult = await fetch('/api/extra/classify/labels', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: getRequestHeaders(),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (apiResult.ok) {
|
|
||||||
const data = await apiResult.json();
|
|
||||||
expressionsList = data.labels;
|
|
||||||
return expressionsList;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const url = new URL(getApiUrl());
|
const url = new URL(getApiUrl());
|
||||||
url.pathname = '/api/classify/labels';
|
url.pathname = '/api/classify/labels';
|
||||||
|
|
||||||
|
@ -1204,6 +1278,17 @@ async function getExpressionsList() {
|
||||||
|
|
||||||
if (apiResult.ok) {
|
if (apiResult.ok) {
|
||||||
|
|
||||||
|
const data = await apiResult.json();
|
||||||
|
expressionsList = data.labels;
|
||||||
|
return expressionsList;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const apiResult = await fetch('/api/extra/classify/labels', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: getRequestHeaders(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (apiResult.ok) {
|
||||||
const data = await apiResult.json();
|
const data = await apiResult.json();
|
||||||
expressionsList = data.labels;
|
expressionsList = data.labels;
|
||||||
return expressionsList;
|
return expressionsList;
|
||||||
|
@ -1444,6 +1529,16 @@ async function onClickExpressionRemoveCustom() {
|
||||||
moduleWorker();
|
moduleWorker();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onExperesionApiChanged() {
|
||||||
|
const tempApi = this.value;
|
||||||
|
if (tempApi) {
|
||||||
|
extension_settings.expressions.api = Number(tempApi);
|
||||||
|
$('.expression_llm_prompt_block').toggle(extension_settings.expressions.api === EXPRESSION_API.llm);
|
||||||
|
moduleWorker();
|
||||||
|
saveSettingsDebounced();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onExpressionFallbackChanged() {
|
function onExpressionFallbackChanged() {
|
||||||
const expression = this.value;
|
const expression = this.value;
|
||||||
if (expression) {
|
if (expression) {
|
||||||
|
@ -1556,6 +1651,7 @@ async function onClickExpressionOverrideButton() {
|
||||||
|
|
||||||
// Refresh sprites list. Assume the override path has been properly handled.
|
// Refresh sprites list. Assume the override path has been properly handled.
|
||||||
try {
|
try {
|
||||||
|
inApiCall = true;
|
||||||
$('#visual-novel-wrapper').empty();
|
$('#visual-novel-wrapper').empty();
|
||||||
await validateImages(overridePath.length === 0 ? currentLastMessage.name : overridePath, true);
|
await validateImages(overridePath.length === 0 ? currentLastMessage.name : overridePath, true);
|
||||||
const expression = await getExpressionLabel(currentLastMessage.mes);
|
const expression = await getExpressionLabel(currentLastMessage.mes);
|
||||||
|
@ -1563,6 +1659,8 @@ async function onClickExpressionOverrideButton() {
|
||||||
forceUpdateVisualNovelMode();
|
forceUpdateVisualNovelMode();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.debug(`Setting expression override for ${avatarFileName} failed with error: ${error}`);
|
console.debug(`Setting expression override for ${avatarFileName} failed with error: ${error}`);
|
||||||
|
} finally {
|
||||||
|
inApiCall = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1699,6 +1797,22 @@ async function fetchImagesNoCache() {
|
||||||
return await Promise.allSettled(promises);
|
return await Promise.allSettled(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function migrateSettings() {
|
||||||
|
if (Object.keys(extension_settings.expressions).includes('local')) {
|
||||||
|
if (extension_settings.expressions.local) {
|
||||||
|
extension_settings.expressions.api = EXPRESSION_API.local;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete extension_settings.expressions.local;
|
||||||
|
saveSettingsDebounced();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extension_settings.expressions.llmPrompt === undefined) {
|
||||||
|
extension_settings.expressions.llmPrompt = DEFAULT_LLM_PROMPT;
|
||||||
|
saveSettingsDebounced();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(async function () {
|
(async function () {
|
||||||
function addExpressionImage() {
|
function addExpressionImage() {
|
||||||
const html = `
|
const html = `
|
||||||
|
@ -1730,11 +1844,6 @@ async function fetchImagesNoCache() {
|
||||||
extension_settings.expressions.translate = !!$(this).prop('checked');
|
extension_settings.expressions.translate = !!$(this).prop('checked');
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
$('#expression_local').prop('checked', extension_settings.expressions.local).on('input', function () {
|
|
||||||
extension_settings.expressions.local = !!$(this).prop('checked');
|
|
||||||
moduleWorker();
|
|
||||||
saveSettingsDebounced();
|
|
||||||
});
|
|
||||||
$('#expression_override_cleanup_button').on('click', onClickExpressionOverrideRemoveAllButton);
|
$('#expression_override_cleanup_button').on('click', onClickExpressionOverrideRemoveAllButton);
|
||||||
$(document).on('dragstart', '.expression', (e) => {
|
$(document).on('dragstart', '.expression', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -1753,10 +1862,23 @@ async function fetchImagesNoCache() {
|
||||||
});
|
});
|
||||||
|
|
||||||
await renderAdditionalExpressionSettings();
|
await renderAdditionalExpressionSettings();
|
||||||
|
$('#expression_api').val(extension_settings.expressions.api ?? EXPRESSION_API.extras);
|
||||||
|
$('.expression_llm_prompt_block').toggle(extension_settings.expressions.api === EXPRESSION_API.llm);
|
||||||
|
$('#expression_llm_prompt').val(extension_settings.expressions.llmPrompt ?? '');
|
||||||
|
$('#expression_llm_prompt').on('input', function () {
|
||||||
|
extension_settings.expressions.llmPrompt = $(this).val();
|
||||||
|
saveSettingsDebounced();
|
||||||
|
});
|
||||||
|
$('#expression_llm_prompt_restore').on('click', function () {
|
||||||
|
$('#expression_llm_prompt').val(DEFAULT_LLM_PROMPT);
|
||||||
|
extension_settings.expressions.llmPrompt = DEFAULT_LLM_PROMPT;
|
||||||
|
saveSettingsDebounced();
|
||||||
|
});
|
||||||
|
|
||||||
$('#expression_custom_add').on('click', onClickExpressionAddCustom);
|
$('#expression_custom_add').on('click', onClickExpressionAddCustom);
|
||||||
$('#expression_custom_remove').on('click', onClickExpressionRemoveCustom);
|
$('#expression_custom_remove').on('click', onClickExpressionRemoveCustom);
|
||||||
$('#expression_fallback').on('change', onExpressionFallbackChanged);
|
$('#expression_fallback').on('change', onExpressionFallbackChanged);
|
||||||
|
$('#expression_api').on('change', onExperesionApiChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pause Talkinghead to save resources when the ST tab is not visible or the window is minimized.
|
// Pause Talkinghead to save resources when the ST tab is not visible or the window is minimized.
|
||||||
|
@ -1789,6 +1911,7 @@ async function fetchImagesNoCache() {
|
||||||
|
|
||||||
addExpressionImage();
|
addExpressionImage();
|
||||||
addVisualNovelMode();
|
addVisualNovelMode();
|
||||||
|
migrateSettings();
|
||||||
await addSettings();
|
await addSettings();
|
||||||
const wrapper = new ModuleWorkerWrapper(moduleWorker);
|
const wrapper = new ModuleWorkerWrapper(moduleWorker);
|
||||||
const updateFunction = wrapper.update.bind(wrapper);
|
const updateFunction = wrapper.update.bind(wrapper);
|
||||||
|
@ -1828,6 +1951,7 @@ async function fetchImagesNoCache() {
|
||||||
});
|
});
|
||||||
eventSource.on(event_types.MOVABLE_PANELS_RESET, updateVisualNovelModeDebounced);
|
eventSource.on(event_types.MOVABLE_PANELS_RESET, updateVisualNovelModeDebounced);
|
||||||
eventSource.on(event_types.GROUP_UPDATED, updateVisualNovelModeDebounced);
|
eventSource.on(event_types.GROUP_UPDATED, updateVisualNovelModeDebounced);
|
||||||
|
eventSource.on(event_types.TEXT_COMPLETION_SETTINGS_READY, onTextGenSettingsReady);
|
||||||
registerSlashCommand('sprite', setSpriteSlashCommand, ['emote'], '<span class="monospace">(spriteId)</span> – force sets the sprite for the current character', true, true);
|
registerSlashCommand('sprite', setSpriteSlashCommand, ['emote'], '<span class="monospace">(spriteId)</span> – force sets the sprite for the current character', true, true);
|
||||||
registerSlashCommand('spriteoverride', setSpriteSetCommand, ['costume'], '<span class="monospace">(optional folder)</span> – sets an override sprite folder for the current character. If the name starts with a slash or a backslash, selects a sub-folder in the character-named folder. Empty value to reset to default.', true, true);
|
registerSlashCommand('spriteoverride', setSpriteSetCommand, ['costume'], '<span class="monospace">(optional folder)</span> – sets an override sprite folder for the current character. If the name starts with a slash or a backslash, selects a sub-folder in the character-named folder. Empty value to reset to default.', true, true);
|
||||||
registerSlashCommand('lastsprite', (_, value) => lastExpression[value.trim()] ?? '', [], '<span class="monospace">(charName)</span> – Returns the last set sprite / expression for the named character.', true, true);
|
registerSlashCommand('lastsprite', (_, value) => lastExpression[value.trim()] ?? '', [], '<span class="monospace">(charName)</span> – Returns the last set sprite / expression for the named character.', true, true);
|
||||||
|
|
|
@ -6,10 +6,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="inline-drawer-content">
|
<div class="inline-drawer-content">
|
||||||
<label class="checkbox_label" for="expression_local" title="Use classification model without the Extras server.">
|
|
||||||
<input id="expression_local" type="checkbox" />
|
|
||||||
<span data-i18n="Local server classification">Local server classification</span>
|
|
||||||
</label>
|
|
||||||
<label class="checkbox_label" for="expression_translate" title="Use the selected API from Chat Translation extension settings.">
|
<label class="checkbox_label" for="expression_translate" title="Use the selected API from Chat Translation extension settings.">
|
||||||
<input id="expression_translate" type="checkbox">
|
<input id="expression_translate" type="checkbox">
|
||||||
<span>Translate text to English before classification</span>
|
<span>Translate text to English before classification</span>
|
||||||
|
@ -22,6 +18,25 @@
|
||||||
<input id="image_type_toggle" type="checkbox">
|
<input id="image_type_toggle" type="checkbox">
|
||||||
<span>Image Type - talkinghead (extras)</span>
|
<span>Image Type - talkinghead (extras)</span>
|
||||||
</label>
|
</label>
|
||||||
|
<div class="expression_api_block m-b-1 m-t-1">
|
||||||
|
<label for="expression_api">Classifier API</label>
|
||||||
|
<small>Select the API for classifying expressions.</small>
|
||||||
|
<select id="expression_api" class="flex1 margin0" data-i18n="Expression API" placeholder="Expression API">
|
||||||
|
<option value="0">Local</option>
|
||||||
|
<option value="1">Extras</option>
|
||||||
|
<option value="2">LLM</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="expression_llm_prompt_block m-b-1 m-t-1">
|
||||||
|
<label for="expression_llm_prompt" class="title_restorable">
|
||||||
|
<span>LLM Prompt</span>
|
||||||
|
<div id="expression_llm_prompt_restore" title="Restore default value" class="right_menu_button">
|
||||||
|
<i class="fa-solid fa-clock-rotate-left fa-sm"></i>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<small>Will be used if the API doesn't support JSON schemas.</small>
|
||||||
|
<textarea id="expression_llm_prompt" type="text" class="text_pole textarea_compact" rows="2" placeholder="Use {{labels}} special macro."></textarea>
|
||||||
|
</div>
|
||||||
<div class="expression_fallback_block m-b-1 m-t-1">
|
<div class="expression_fallback_block m-b-1 m-t-1">
|
||||||
<label for="expression_fallback">Default / Fallback Expression</label>
|
<label for="expression_fallback">Default / Fallback Expression</label>
|
||||||
<small>Set the default and fallback expression being used when no matching expression is found.</small>
|
<small>Set the default and fallback expression being used when no matching expression is found.</small>
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {
|
||||||
event_types,
|
event_types,
|
||||||
getRequestHeaders,
|
getRequestHeaders,
|
||||||
getStoppingStrings,
|
getStoppingStrings,
|
||||||
|
main_api,
|
||||||
max_context,
|
max_context,
|
||||||
saveSettingsDebounced,
|
saveSettingsDebounced,
|
||||||
setGenerationParamsFromPreset,
|
setGenerationParamsFromPreset,
|
||||||
|
@ -978,6 +979,10 @@ function getModel() {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isJsonSchemaSupported() {
|
||||||
|
return settings.type === TABBY && main_api === 'textgenerationwebui';
|
||||||
|
}
|
||||||
|
|
||||||
export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, isContinue, cfgValues, type) {
|
export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, isContinue, cfgValues, type) {
|
||||||
const canMultiSwipe = !isContinue && !isImpersonate && type !== 'quiet';
|
const canMultiSwipe = !isContinue && !isImpersonate && type !== 'quiet';
|
||||||
let params = {
|
let params = {
|
||||||
|
|
Loading…
Reference in New Issue