Merge branch 'staging' into neo-server

This commit is contained in:
Cohee 2024-04-15 00:26:52 +03:00
commit 0263be8c1f
10 changed files with 276 additions and 81 deletions

View File

@ -68,6 +68,8 @@ module.exports = {
'no-trailing-spaces': 'error',
'object-curly-spacing': ['error', 'always'],
'space-infix-ops': 'error',
'no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }],
'no-cond-assign': 'error',
// These rules should eventually be enabled.
'no-async-promise-executor': 'off',

View File

@ -4,9 +4,6 @@
padding: 0;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 999999;
width: 100vw;
height: 100vh;
@ -20,6 +17,15 @@
}
#load-spinner {
--spinner-size: 2em;
transition: all 300ms ease-out;
opacity: 1;
top: calc(50% - var(--spinner-size) / 2);
left: calc(50% - var(--spinner-size) / 2);
position: absolute;
width: var(--spinner-size);
height: var(--spinner-size);
display: flex;
align-items: center;
justify-content: center;
}

View File

@ -459,6 +459,17 @@
</span>
</div>
</div>
<div class="range-block" data-source="cohere">
<label for="websearch_toggle" title="Enable Cohere web-search connector" data-i18n="[title]Enable Cohere web-search connector" class="checkbox_label widthFreeExpand">
<input id="websearch_toggle" type="checkbox" />
<span data-i18n="Web-search">Web-search</span>
</label>
<div class="toggle-description justifyLeft">
<span data-i18n="Allow the model to use the web-search connector.">
Allow the model to use the web-search connector.
</span>
</div>
</div>
<div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai,custom,cohere">
<div class="range-block-title" data-i18n="Temperature">
Temperature
@ -3848,7 +3859,7 @@
<input id="prefer_character_jailbreak" type="checkbox" />
<span data-i18n="Prefer Character Card Jailbreak">Prefer Char. Jailbreak</span>
</label>
<label data-newbie-hidden class="checkbox_label" for="never_resize_avatars" title="Avoid cropping and resizing imported character images. When off, crop/resize to 400x600." data-i18n="[title]Avoid cropping and resizing imported character images. When off, crop/resize to 400x600">
<label data-newbie-hidden class="checkbox_label" for="never_resize_avatars" title="Avoid cropping and resizing imported character images. When off, crop/resize to 512x768." data-i18n="[title]Avoid cropping and resizing imported character images. When off, crop/resize to 512x768">
<input id="never_resize_avatars" type="checkbox" />
<span data-i18n="Never resize avatars">Never resize avatars</span>
</label>

View File

@ -858,11 +858,11 @@ async function firstLoadInit() {
throw new Error('Initialization failed');
}
await readSecretState();
await getSettings();
await getSystemMessages();
sendSystemMessage(system_message_types.WELCOME);
await getClientVersion();
await readSecretState();
await getSettings();
initLocales();
initTags();
await getUserAvatars(true, user_avatar);
@ -2444,9 +2444,14 @@ function sendSystemMessage(type, text, extra = {}) {
is_send_press = false;
}
/**
* Extracts the contents of bias macros from a message.
* @param {string} message Message text
* @returns {string} Message bias extracted from the message (or an empty string if not found)
*/
export function extractMessageBias(message) {
if (!message) {
return null;
return '';
}
try {
@ -3067,14 +3072,14 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
if (interruptedByCommand) {
//$("#send_textarea").val('').trigger('input');
unblockGeneration();
unblockGeneration(type);
return Promise.resolve();
}
}
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 });
unblockGeneration();
unblockGeneration(type);
return Promise.resolve();
}
@ -3083,12 +3088,12 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
textgen_settings.legacy_api &&
(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 });
unblockGeneration();
unblockGeneration(type);
return Promise.resolve();
}
if (isHordeGenerationNotAllowed()) {
unblockGeneration();
unblockGeneration(type);
return Promise.resolve();
}
@ -3124,7 +3129,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
setCharacterName('');
} else {
console.log('No enabled members found');
unblockGeneration();
unblockGeneration(type);
return Promise.resolve();
}
}
@ -3298,7 +3303,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
if (aborted) {
console.debug('Generation aborted by extension interceptors');
unblockGeneration();
unblockGeneration(type);
return Promise.resolve();
}
} else {
@ -3312,7 +3317,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
adjustedParams = await adjustHordeGenerationParams(max_context, amount_gen);
}
catch {
unblockGeneration();
unblockGeneration(type);
return Promise.resolve();
}
if (horde_settings.auto_adjust_context_length) {
@ -4099,7 +4104,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
await eventSource.emit(event_types.IMPERSONATE_READY, getMessage);
}
else if (type == 'quiet') {
unblockGeneration();
unblockGeneration(type);
return getMessage;
}
else {
@ -4167,7 +4172,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
console.debug('/api/chats/save called by /Generate');
await saveChatConditional();
unblockGeneration();
unblockGeneration(type);
streamingProcessor = null;
if (type !== 'quiet') {
@ -4185,7 +4190,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
generatedPromptCache = '';
unblockGeneration();
unblockGeneration(type);
console.log(exception);
streamingProcessor = null;
throw exception;
@ -4255,7 +4260,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;
activateSendButtons();
showSwipeButtons();

View File

@ -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 { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js';
import { loadMovingUIState, power_user } from '../../power-user.js';
import { registerSlashCommand } from '../../slash-commands.js';
import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence } from '../../utils.js';
import { hideMutedSprites } from '../../group-chats.js';
import { isJsonSchemaSupported } from '../../textgen-settings.js';
export { MODULE_NAME };
const MODULE_NAME = 'expressions';
const UPDATE_INTERVAL = 2000;
const STREAMING_UPDATE_INTERVAL = 6000;
const STREAMING_UPDATE_INTERVAL = 10000;
const TALKINGCHECK_UPDATE_INTERVAL = 500;
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 = [
'talkinghead',
'admiration',
@ -43,6 +45,11 @@ const DEFAULT_EXPRESSIONS = [
'surprise',
'neutral',
];
const EXPRESSION_API = {
local: 0,
extras: 1,
llm: 2,
};
let expressionsList = null;
let lastCharacter = undefined;
@ -55,7 +62,7 @@ let lastServerResponseTime = 0;
export let lastExpression = {};
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() {
const context = getContext();
// Hide and disable Talkinghead while in local mode
$('#image_type_block').toggle(!extension_settings.expressions.local);
// Hide and disable Talkinghead while not in extras
$('#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);
setTalkingHeadState(false);
}
@ -628,7 +635,7 @@ async function moduleWorker() {
}
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();
$('#no_chat_expressions').hide();
offlineMode.css('display', 'block');
@ -821,7 +828,7 @@ function setTalkingHeadState(newState) {
extension_settings.expressions.talkinghead = newState; // Store setting
saveSettingsDebounced();
if (extension_settings.expressions.local) {
if (extension_settings.expressions.api == EXPRESSION_API.local || extension_settings.expressions.api == EXPRESSION_API.llm) {
return;
}
@ -900,7 +907,7 @@ async function classifyCommand(_, text) {
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');
return '';
}
@ -971,9 +978,76 @@ function sampleClassifyText(text) {
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) {
// 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();
}
@ -984,39 +1058,50 @@ async function getExpressionLabel(text) {
text = sampleClassifyText(text);
try {
if (extension_settings.expressions.local) {
// Local transformers pipeline
const apiResult = await fetch('/api/extra/classify', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ text: text }),
});
switch (extension_settings.expressions.api) {
// Local BERT pipeline
case EXPRESSION_API.local: {
const localResult = await fetch('/api/extra/classify', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ text: text }),
});
if (apiResult.ok) {
const data = await apiResult.json();
return data.classification[0].label;
if (localResult.ok) {
const data = await localResult.json();
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
const url = new URL(getApiUrl());
url.pathname = '/api/classify';
default: {
const url = new URL(getApiUrl());
url.pathname = '/api/classify';
const apiResult = await doExtrasFetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Bypass-Tunnel-Reminder': 'bypass',
},
body: JSON.stringify({ text: text }),
});
const extrasResult = await doExtrasFetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Bypass-Tunnel-Reminder': 'bypass',
},
body: JSON.stringify({ text: text }),
});
if (apiResult.ok) {
const data = await apiResult.json();
return data.classification[0].label;
}
if (extrasResult.ok) {
const data = await extrasResult.json();
return data.classification[0].label;
}
} break;
}
} 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();
}
}
@ -1177,23 +1262,12 @@ async function getExpressionsList() {
*/
async function resolveExpressionsList() {
// 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;
}
try {
if (extension_settings.expressions.local) {
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 {
if (extension_settings.expressions.api == EXPRESSION_API.extras) {
const url = new URL(getApiUrl());
url.pathname = '/api/classify/labels';
@ -1204,6 +1278,17 @@ async function getExpressionsList() {
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();
expressionsList = data.labels;
return expressionsList;
@ -1444,6 +1529,16 @@ async function onClickExpressionRemoveCustom() {
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() {
const expression = this.value;
if (expression) {
@ -1556,6 +1651,7 @@ async function onClickExpressionOverrideButton() {
// Refresh sprites list. Assume the override path has been properly handled.
try {
inApiCall = true;
$('#visual-novel-wrapper').empty();
await validateImages(overridePath.length === 0 ? currentLastMessage.name : overridePath, true);
const expression = await getExpressionLabel(currentLastMessage.mes);
@ -1563,6 +1659,8 @@ async function onClickExpressionOverrideButton() {
forceUpdateVisualNovelMode();
} catch (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);
}
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 () {
function addExpressionImage() {
const html = `
@ -1730,11 +1844,6 @@ async function fetchImagesNoCache() {
extension_settings.expressions.translate = !!$(this).prop('checked');
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);
$(document).on('dragstart', '.expression', (e) => {
e.preventDefault();
@ -1753,10 +1862,23 @@ async function fetchImagesNoCache() {
});
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_remove').on('click', onClickExpressionRemoveCustom);
$('#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.
@ -1789,6 +1911,7 @@ async function fetchImagesNoCache() {
addExpressionImage();
addVisualNovelMode();
migrateSettings();
await addSettings();
const wrapper = new ModuleWorkerWrapper(moduleWorker);
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.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('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);

View File

@ -6,10 +6,6 @@
</div>
<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.">
<input id="expression_translate" type="checkbox">
<span>Translate text to English before classification</span>
@ -22,6 +18,25 @@
<input id="image_type_toggle" type="checkbox">
<span>Image Type - talkinghead (extras)</span>
</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 &lcub;&lcub;labels&rcub;&rcub; special macro."></textarea>
</div>
<div class="expression_fallback_block m-b-1 m-t-1">
<label for="expression_fallback">Default / Fallback Expression</label>
<small>Set the default and fallback expression being used when no matching expression is found.</small>

View File

@ -214,6 +214,7 @@ const default_settings = {
top_a_openai: 1,
repetition_penalty_openai: 1,
stream_openai: false,
websearch_cohere: false,
openai_max_context: max_4k,
openai_max_tokens: 300,
wrap_in_quotes: false,
@ -285,6 +286,7 @@ const oai_settings = {
top_a_openai: 1,
repetition_penalty_openai: 1,
stream_openai: false,
websearch_cohere: false,
openai_max_context: max_4k,
openai_max_tokens: 300,
wrap_in_quotes: false,
@ -1764,6 +1766,7 @@ async function sendOpenAIRequest(type, messages, signal) {
generate_data['frequency_penalty'] = Math.min(Math.max(Number(oai_settings.freq_pen_openai), 0), 1);
generate_data['presence_penalty'] = Math.min(Math.max(Number(oai_settings.pres_pen_openai), 0), 1);
generate_data['stop'] = getCustomStoppingStrings(5);
generate_data['websearch'] = oai_settings.websearch_cohere;
}
if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere) && oai_settings.seed >= 0) {
@ -2611,6 +2614,7 @@ function loadOpenAISettings(data, settings) {
oai_settings.min_p_openai = settings.min_p_openai ?? default_settings.min_p_openai;
oai_settings.repetition_penalty_openai = settings.repetition_penalty_openai ?? default_settings.repetition_penalty_openai;
oai_settings.stream_openai = settings.stream_openai ?? default_settings.stream_openai;
oai_settings.websearch_cohere = settings.websearch_cohere ?? default_settings.websearch_cohere;
oai_settings.openai_max_context = settings.openai_max_context ?? default_settings.openai_max_context;
oai_settings.openai_max_tokens = settings.openai_max_tokens ?? default_settings.openai_max_tokens;
oai_settings.bias_preset_selected = settings.bias_preset_selected ?? default_settings.bias_preset_selected;
@ -2674,6 +2678,7 @@ function loadOpenAISettings(data, settings) {
if (settings.use_makersuite_sysprompt !== undefined) oai_settings.use_makersuite_sysprompt = !!settings.use_makersuite_sysprompt;
if (settings.use_alt_scale !== undefined) { oai_settings.use_alt_scale = !!settings.use_alt_scale; updateScaleForm(); }
$('#stream_toggle').prop('checked', oai_settings.stream_openai);
$('#websearch_toggle').prop('checked', oai_settings.websearch_cohere);
$('#api_url_scale').val(oai_settings.api_url_scale);
$('#openai_proxy_password').val(oai_settings.proxy_password);
$('#claude_assistant_prefill').val(oai_settings.assistant_prefill);
@ -2972,6 +2977,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
personality_format: settings.personality_format,
group_nudge_prompt: settings.group_nudge_prompt,
stream_openai: settings.stream_openai,
websearch_cohere: settings.websearch_cohere,
prompts: settings.prompts,
prompt_order: settings.prompt_order,
api_url_scale: settings.api_url_scale,
@ -3350,6 +3356,7 @@ function onSettingsPresetChange() {
personality_format: ['#personality_format_textarea', 'personality_format', false],
group_nudge_prompt: ['#group_nudge_prompt_textarea', 'group_nudge_prompt', false],
stream_openai: ['#stream_toggle', 'stream_openai', true],
websearch_cohere: ['#websearch_toggle', 'websearch_cohere', true],
prompts: ['', 'prompts', false],
prompt_order: ['', 'prompt_order', false],
api_url_scale: ['#api_url_scale', 'api_url_scale', false],
@ -4171,8 +4178,7 @@ $('#delete_proxy').on('click', async function () {
function runProxyCallback(_, value) {
if (!value) {
toastr.warning('Proxy preset name is required');
return '';
return selected_proxy?.name || '';
}
const proxyNames = proxies.map(preset => preset.name);
@ -4272,6 +4278,11 @@ $(document).ready(async function () {
saveSettingsDebounced();
});
$('#websearch_toggle').on('change', function () {
oai_settings.websearch_cohere = !!$('#websearch_toggle').prop('checked');
saveSettingsDebounced();
});
$('#wrap_in_quotes').on('change', function () {
oai_settings.wrap_in_quotes = !!$('#wrap_in_quotes').prop('checked');
saveSettingsDebounced();

View File

@ -3,6 +3,7 @@ import {
event_types,
getRequestHeaders,
getStoppingStrings,
main_api,
max_context,
saveSettingsDebounced,
setGenerationParamsFromPreset,
@ -978,6 +979,10 @@ function getModel() {
return undefined;
}
export function isJsonSchemaSupported() {
return settings.type === TABBY && main_api === 'textgenerationwebui';
}
export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, isContinue, cfgValues, type) {
const canMultiSwipe = !isContinue && !isImpersonate && type !== 'quiet';
let params = {

View File

@ -271,8 +271,8 @@ const OLLAMA_KEYS = [
'mirostat_eta',
];
const AVATAR_WIDTH = 400;
const AVATAR_HEIGHT = 600;
const AVATAR_WIDTH = 512;
const AVATAR_HEIGHT = 768;
const OPENROUTER_HEADERS = {
'HTTP-Referer': 'https://sillytavern.app',

View File

@ -567,6 +567,13 @@ async function sendCohereRequest(request, response) {
try {
const convertedHistory = convertCohereMessages(request.body.messages, request.body.char_name, request.body.user_name);
const connectors = [];
if (request.body.websearch) {
connectors.push({
id: 'web-search',
});
}
// https://docs.cohere.com/reference/chat
const requestBody = {
@ -584,7 +591,7 @@ async function sendCohereRequest(request, response) {
frequency_penalty: request.body.frequency_penalty,
presence_penalty: request.body.presence_penalty,
prompt_truncation: 'AUTO_PRESERVE_ORDER',
connectors: [], // TODO
connectors: connectors,
documents: [],
tools: [],
tool_results: [],