mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Merge branch 'staging' into support-multiple-expressions
This commit is contained in:
@ -54,6 +54,8 @@
|
||||
<option data-type="anthropic" value="claude-3-sonnet-20240229">claude-3-sonnet-20240229</option>
|
||||
<option data-type="anthropic" value="claude-3-haiku-20240307">claude-3-haiku-20240307</option>
|
||||
<option data-type="google" value="gemini-2.0-flash-exp">gemini-2.0-flash-exp</option>
|
||||
<option data-type="google" value="gemini-2.0-flash-thinking-exp">gemini-2.0-flash-thinking-exp</option>
|
||||
<option data-type="google" value="gemini-2.0-flash-thinking-exp-01-21">gemini-2.0-flash-thinking-exp-01-21</option>
|
||||
<option data-type="google" value="gemini-2.0-flash-thinking-exp-1219">gemini-2.0-flash-thinking-exp-1219</option>
|
||||
<option data-type="google" value="gemini-1.5-flash">gemini-1.5-flash</option>
|
||||
<option data-type="google" value="gemini-1.5-flash-latest">gemini-1.5-flash-latest</option>
|
||||
|
@ -1,10 +1,10 @@
|
||||
<div>
|
||||
<h3>Included settings:</h3>
|
||||
<h3 data-i18n="Included settings:">Included settings:</h3>
|
||||
<div class="justifyLeft flex-container flexFlowColumn flexNoGap">
|
||||
{{#each settings}}
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" value="{{@key}}" name="exclude"{{#if this}} checked{{/if}}>
|
||||
<span>{{@key}}</span>
|
||||
<span data-i18n="{{@key}}">{{@key}}</span>
|
||||
</label>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
@ -12,8 +12,8 @@
|
||||
</div>
|
||||
<div class="marginTop5">
|
||||
<small>
|
||||
<b>Hint:</b>
|
||||
<i>Click on the setting name to omit it from the profile.</i>
|
||||
<b data-i18n="Hint:">Hint:</b>
|
||||
<i data-i18n="Click on the setting name to omit it from the profile.">Click on the setting name to omit it from the profile.</i>
|
||||
</small>
|
||||
</div>
|
||||
<h3 data-i18n="Enter a name:">
|
||||
|
@ -277,7 +277,7 @@ function makeMovable(id = 'gallery') {
|
||||
const newElement = $(template);
|
||||
newElement.css('background-color', 'var(--SmartThemeBlurTintColor)');
|
||||
newElement.attr('forChar', id);
|
||||
newElement.attr('id', `${id}`);
|
||||
newElement.attr('id', id);
|
||||
newElement.find('.drag-grabber').attr('id', `${id}header`);
|
||||
newElement.find('.dragTitle').text('Image Gallery');
|
||||
//add a div for the gallery
|
||||
|
@ -46,10 +46,12 @@
|
||||
<div class="qr--title" data-i18n="Edit Quick Replies">Edit Quick Replies</div>
|
||||
<div class="qr--actions">
|
||||
<select id="qr--set" class="text_pole"></select>
|
||||
<div class="qr--add menu_button menu_button_icon fa-solid fa-pencil" id="qr--set-rename" title="Rename quick reply set"></div>
|
||||
<div class="qr--add menu_button menu_button_icon fa-solid fa-plus" id="qr--set-new" title="Create new quick reply set"></div>
|
||||
<div class="qr--add menu_button menu_button_icon fa-solid fa-file-import" id="qr--set-import" title="Import quick reply set"></div>
|
||||
<input type="file" id="qr--set-importFile" accept=".json" hidden>
|
||||
<div class="qr--add menu_button menu_button_icon fa-solid fa-file-export" id="qr--set-export" title="Export quick reply set"></div>
|
||||
<div class="qr-add menu_button menu_button_icon fa-solid fa-paste" id="qr--set-duplicate" title="Duplicate quick reply set"></div>
|
||||
<div class="qr--del menu_button menu_button_icon fa-solid fa-trash redWarningBG" id="qr--set-delete" title="Delete quick reply set"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { callPopup } from '../../../../../script.js';
|
||||
import { Popup } from '../../../../popup.js';
|
||||
import { getSortableDelay } from '../../../../utils.js';
|
||||
import { log, warn } from '../../index.js';
|
||||
import { QuickReply } from '../QuickReply.js';
|
||||
@ -111,6 +111,7 @@ export class SettingsUi {
|
||||
|
||||
prepareQrEditor() {
|
||||
// qr editor
|
||||
this.dom.querySelector('#qr--set-rename').addEventListener('click', async () => this.renameQrSet());
|
||||
this.dom.querySelector('#qr--set-new').addEventListener('click', async()=>this.addQrSet());
|
||||
/**@type {HTMLInputElement}*/
|
||||
const importFile = this.dom.querySelector('#qr--set-importFile');
|
||||
@ -119,7 +120,8 @@ export class SettingsUi {
|
||||
importFile.value = null;
|
||||
});
|
||||
this.dom.querySelector('#qr--set-import').addEventListener('click', ()=>importFile.click());
|
||||
this.dom.querySelector('#qr--set-export').addEventListener('click', async()=>this.exportQrSet());
|
||||
this.dom.querySelector('#qr--set-export').addEventListener('click', async () => this.exportQrSet());
|
||||
this.dom.querySelector('#qr--set-duplicate').addEventListener('click', async () => this.duplicateQrSet());
|
||||
this.dom.querySelector('#qr--set-delete').addEventListener('click', async()=>this.deleteQrSet());
|
||||
this.dom.querySelector('#qr--set-add').addEventListener('click', async()=>{
|
||||
this.currentQrSet.addQuickReply();
|
||||
@ -279,7 +281,7 @@ export class SettingsUi {
|
||||
}
|
||||
|
||||
async deleteQrSet() {
|
||||
const confirmed = await callPopup(`Are you sure you want to delete the Quick Reply Set "${this.currentQrSet.name}"?<br>This cannot be undone.`, 'confirm');
|
||||
const confirmed = await Popup.show.confirm('Delete Quick Reply Set', `Are you sure you want to delete the Quick Reply Set "${this.currentQrSet.name}"?<br>This cannot be undone.`);
|
||||
if (confirmed) {
|
||||
await this.doDeleteQrSet(this.currentQrSet);
|
||||
this.rerender();
|
||||
@ -303,12 +305,52 @@ export class SettingsUi {
|
||||
this.settings.save();
|
||||
}
|
||||
|
||||
async renameQrSet() {
|
||||
const newName = await Popup.show.input('Rename Quick Reply Set', 'Enter a new name:', this.currentQrSet.name);
|
||||
if (newName && newName.length > 0) {
|
||||
const existingSet = QuickReplySet.get(newName);
|
||||
if (existingSet) {
|
||||
toastr.error(`A Quick Reply Set named "${newName}" already exists.`);
|
||||
return;
|
||||
}
|
||||
const oldName = this.currentQrSet.name;
|
||||
this.currentQrSet.name = newName;
|
||||
await this.currentQrSet.save();
|
||||
|
||||
// Update it in both set lists
|
||||
this.settings.config.setList.forEach(set => {
|
||||
if (set.set.name === oldName) {
|
||||
set.set.name = newName;
|
||||
}
|
||||
});
|
||||
this.settings.chatConfig?.setList.forEach(set => {
|
||||
if (set.set.name === oldName) {
|
||||
set.set.name = newName;
|
||||
}
|
||||
});
|
||||
this.settings.save();
|
||||
|
||||
// Update the option in the current selected QR dropdown. All others will be refreshed via the prepare calls below.
|
||||
/** @type {HTMLOptionElement} */
|
||||
const option = this.currentSet.querySelector(`#qr--set option[value="${oldName}"]`);
|
||||
option.value = newName;
|
||||
option.textContent = newName;
|
||||
|
||||
this.currentSet.value = newName;
|
||||
this.onQrSetChange();
|
||||
this.prepareGlobalSetList();
|
||||
this.prepareChatSetList();
|
||||
|
||||
console.info(`Quick Reply Set renamed from ""${oldName}" to "${newName}".`);
|
||||
}
|
||||
}
|
||||
|
||||
async addQrSet() {
|
||||
const name = await callPopup('Quick Reply Set Name:', 'input');
|
||||
const name = await Popup.show.input('Create a new World Info', 'Enter a name for the new Quick Reply Set:');
|
||||
if (name && name.length > 0) {
|
||||
const oldQrs = QuickReplySet.get(name);
|
||||
if (oldQrs) {
|
||||
const replace = await callPopup(`A Quick Reply Set named "${name}" already exists.<br>Do you want to overwrite the existing Quick Reply Set?<br>The existing set will be deleted. This cannot be undone.`, 'confirm');
|
||||
const replace = Popup.show.confirm('Replace existing World Info', `A Quick Reply Set named "${name}" already exists.<br>Do you want to overwrite the existing Quick Reply Set?<br>The existing set will be deleted. This cannot be undone.`);
|
||||
if (replace) {
|
||||
const idx = QuickReplySet.list.indexOf(oldQrs);
|
||||
await this.doDeleteQrSet(oldQrs);
|
||||
@ -369,7 +411,7 @@ export class SettingsUi {
|
||||
qrs.init();
|
||||
const oldQrs = QuickReplySet.get(props.name);
|
||||
if (oldQrs) {
|
||||
const replace = await callPopup(`A Quick Reply Set named "${qrs.name}" already exists.<br>Do you want to overwrite the existing Quick Reply Set?<br>The existing set will be deleted. This cannot be undone.`, 'confirm');
|
||||
const replace = Popup.show.confirm('Replace existing World Info', `A Quick Reply Set named "${name}" already exists.<br>Do you want to overwrite the existing Quick Reply Set?<br>The existing set will be deleted. This cannot be undone.`);
|
||||
if (replace) {
|
||||
const idx = QuickReplySet.list.indexOf(oldQrs);
|
||||
await this.doDeleteQrSet(oldQrs);
|
||||
@ -421,6 +463,40 @@ export class SettingsUi {
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
async duplicateQrSet() {
|
||||
const newName = await Popup.show.input('Duplicate Quick Reply Set', 'Enter a name for the new Quick Reply Set:', `${this.currentQrSet.name} (Copy)`);
|
||||
if (newName && newName.length > 0) {
|
||||
const existingSet = QuickReplySet.get(newName);
|
||||
if (existingSet) {
|
||||
toastr.error(`A Quick Reply Set named "${newName}" already exists.`);
|
||||
return;
|
||||
}
|
||||
const newQrSet = QuickReplySet.from(JSON.parse(JSON.stringify(this.currentQrSet)));
|
||||
newQrSet.name = newName;
|
||||
newQrSet.qrList = this.currentQrSet.qrList.map(qr => QuickReply.from(JSON.parse(JSON.stringify(qr))));
|
||||
newQrSet.addQuickReply();
|
||||
const idx = QuickReplySet.list.findIndex(it => it.name.toLowerCase().localeCompare(newName.toLowerCase()) == 1);
|
||||
if (idx > -1) {
|
||||
QuickReplySet.list.splice(idx, 0, newQrSet);
|
||||
} else {
|
||||
QuickReplySet.list.push(newQrSet);
|
||||
}
|
||||
const opt = document.createElement('option'); {
|
||||
opt.value = newQrSet.name;
|
||||
opt.textContent = newQrSet.name;
|
||||
if (idx > -1) {
|
||||
this.currentSet.children[idx].insertAdjacentElement('beforebegin', opt);
|
||||
} else {
|
||||
this.currentSet.append(opt);
|
||||
}
|
||||
}
|
||||
this.currentSet.value = newName;
|
||||
this.onQrSetChange();
|
||||
this.prepareGlobalSetList();
|
||||
this.prepareChatSetList();
|
||||
}
|
||||
}
|
||||
|
||||
selectQrSet(qrs) {
|
||||
this.currentSet.value = qrs.name;
|
||||
this.onQrSetChange();
|
||||
|
@ -388,7 +388,7 @@ class AllTalkTtsProvider {
|
||||
}
|
||||
|
||||
async fetchRvcVoiceObjects() {
|
||||
if (this.settings.server_version !== 'v2') {
|
||||
if (this.settings.server_version == 'v2') {
|
||||
console.log('Skipping RVC voices fetch for V1 server');
|
||||
return [];
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ import { textgen_types, textgenerationwebui_settings } from '../../textgen-setti
|
||||
import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
|
||||
import { SlashCommand } from '../../slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
|
||||
import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
|
||||
import { slashCommandReturnHelper } from '../../slash-commands/SlashCommandReturnHelper.js';
|
||||
import { callGenericPopup, POPUP_RESULT, POPUP_TYPE } from '../../popup.js';
|
||||
import { generateWebLlmChatPrompt, isWebLlmSupported } from '../shared.js';
|
||||
|
||||
@ -1613,25 +1615,55 @@ jQuery(async () => {
|
||||
callback: async (args, query) => {
|
||||
const clamp = (v) => Number.isNaN(v) ? null : Math.min(1, Math.max(0, v));
|
||||
const threshold = clamp(Number(args?.threshold ?? settings.score_threshold));
|
||||
const validateCount = (v) => Number.isNaN(v) || !Number.isInteger(v) || v < 1 ? null : v;
|
||||
const count = validateCount(Number(args?.count)) ?? settings.chunk_count_db;
|
||||
const source = String(args?.source ?? '');
|
||||
const attachments = source ? getDataBankAttachmentsForSource(source, false) : getDataBankAttachments(false);
|
||||
const collectionIds = await ingestDataBankAttachments(String(source));
|
||||
const queryResults = await queryMultipleCollections(collectionIds, String(query), settings.chunk_count_db, threshold);
|
||||
|
||||
// Map collection IDs to file URLs
|
||||
const queryResults = await queryMultipleCollections(collectionIds, String(query), count, threshold);
|
||||
|
||||
// Get URLs
|
||||
const urls = Object
|
||||
.keys(queryResults)
|
||||
.map(x => attachments.find(y => getFileCollectionId(y.url) === x))
|
||||
.filter(x => x)
|
||||
.map(x => x.url);
|
||||
|
||||
// Gets the actual text content of chunks
|
||||
const getChunksText = () => {
|
||||
let textResult = '';
|
||||
for (const collectionId in queryResults) {
|
||||
const metadata = queryResults[collectionId].metadata?.filter(x => x.text)?.sort((a, b) => a.index - b.index)?.map(x => x.text)?.filter(onlyUnique) || [];
|
||||
textResult += metadata.join('\n') + '\n\n';
|
||||
}
|
||||
return textResult;
|
||||
};
|
||||
|
||||
if (args.return === 'chunks') {
|
||||
return getChunksText();
|
||||
}
|
||||
|
||||
return JSON.stringify(urls);
|
||||
// @ts-ignore
|
||||
return slashCommandReturnHelper.doReturn(args.return ?? 'object', urls, { objectToStringFunc: list => list.join('\n') });
|
||||
|
||||
},
|
||||
aliases: ['databank-search', 'data-bank-search'],
|
||||
helpString: 'Search the Data Bank for a specific query using vector similarity. Returns a list of file URLs with the most relevant content.',
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument('threshold', 'Threshold for the similarity score in the [0, 1] range. Uses the global config value if not set.', ARGUMENT_TYPE.NUMBER, false, false, ''),
|
||||
new SlashCommandNamedArgument('count', 'Maximum number of query results to return.', ARGUMENT_TYPE.NUMBER, false, false, ''),
|
||||
new SlashCommandNamedArgument('source', 'Optional filter for the attachments by source.', ARGUMENT_TYPE.STRING, false, false, '', ['global', 'character', 'chat']),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'return',
|
||||
description: 'How you want the return value to be provided',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: 'object',
|
||||
enumList: [
|
||||
new SlashCommandEnumValue('chunks', 'Return the actual content chunks', enumTypes.enum, '{}'),
|
||||
...slashCommandReturnHelper.enumList({ allowObject: true })
|
||||
],
|
||||
forceEnum: true,
|
||||
})
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument('Query to search by.', ARGUMENT_TYPE.STRING, true, false),
|
||||
|
Reference in New Issue
Block a user