mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Add tags as folders display mode
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import { fuzzySearchCharacters, fuzzySearchGroups, fuzzySearchWorldInfo, power_user } from "./power-user.js";
|
||||
import { fuzzySearchCharacters, fuzzySearchGroups, fuzzySearchTags, fuzzySearchWorldInfo, power_user } from "./power-user.js";
|
||||
import { tag_map } from "./tags.js";
|
||||
|
||||
/**
|
||||
@ -148,16 +148,20 @@ export class FilterHelper {
|
||||
const searchValue = this.filterData[FILTER_TYPES.SEARCH].trim().toLowerCase();
|
||||
const fuzzySearchCharactersResults = power_user.fuzzy_search ? fuzzySearchCharacters(searchValue) : [];
|
||||
const fuzzySearchGroupsResults = power_user.fuzzy_search ? fuzzySearchGroups(searchValue) : [];
|
||||
const fuzzySearchTagsResult = power_user.fuzzy_search ? fuzzySearchTags(searchValue) : [];
|
||||
|
||||
function getIsValidSearch(entity) {
|
||||
const isGroup = entity.type === 'group';
|
||||
const isCharacter = entity.type === 'character';
|
||||
const isTag = entity.type === 'tag';
|
||||
|
||||
if (power_user.fuzzy_search) {
|
||||
if (isCharacter) {
|
||||
return fuzzySearchCharactersResults.includes(parseInt(entity.id));
|
||||
} else if (isGroup) {
|
||||
return fuzzySearchGroupsResults.includes(String(entity.id));
|
||||
} else if (isTag) {
|
||||
return fuzzySearchTagsResult.includes(String(entity.id));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import {
|
||||
} from "./instruct-mode.js";
|
||||
|
||||
import { registerSlashCommand } from "./slash-commands.js";
|
||||
import { tags } from "./tags.js";
|
||||
import { tokenizers } from "./tokenizers.js";
|
||||
|
||||
import { countOccurrences, debounce, delay, isOdd, resetScrollHeight, sortMoments, stringToRange, timestampToMoment } from "./utils.js";
|
||||
@ -218,6 +219,7 @@ let power_user = {
|
||||
fuzzy_search: false,
|
||||
encode_tags: false,
|
||||
servers: [],
|
||||
bogus_folders: false,
|
||||
};
|
||||
|
||||
let themes = [];
|
||||
@ -486,7 +488,7 @@ async function switchZenSliders() {
|
||||
$("#clickSlidersTips").hide()
|
||||
$("#pro-settings-block input[type='number']").hide();
|
||||
//hide number inputs that are not 'seed' inputs
|
||||
$(`#textgenerationwebui_api-settings :input[type='number']:not([id^='seed']),
|
||||
$(`#textgenerationwebui_api-settings :input[type='number']:not([id^='seed']),
|
||||
#kobold_api-settings :input[type='number']:not([id^='seed'])`).hide()
|
||||
//hide original sliders
|
||||
$(`#textgenerationwebui_api-settings input[type='range'],
|
||||
@ -1038,7 +1040,14 @@ async function applyTheme(name) {
|
||||
localStorage.setItem(storage_keys.hotswap_enabled, Boolean(power_user.hotswap_enabled));
|
||||
switchHotswap();
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'bogus_folders',
|
||||
action: async () => {
|
||||
$('#bogus_folders').prop('checked', power_user.bogus_folders);
|
||||
await printCharacters(true);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (const { key, selector, type, action } of themeProperties) {
|
||||
@ -1203,6 +1212,7 @@ function loadPowerUserSettings(settings, data) {
|
||||
$("#console_log_prompts").prop("checked", power_user.console_log_prompts);
|
||||
$('#auto_fix_generated_markdown').prop("checked", power_user.auto_fix_generated_markdown);
|
||||
$('#auto_scroll_chat_to_bottom').prop("checked", power_user.auto_scroll_chat_to_bottom);
|
||||
$('#bogus_folders').prop("checked", power_user.bogus_folders);
|
||||
$(`#tokenizer option[value="${power_user.tokenizer}"]`).attr('selected', true);
|
||||
$(`#send_on_enter option[value=${power_user.send_on_enter}]`).attr("selected", true);
|
||||
$("#import_card_tags").prop("checked", power_user.import_card_tags);
|
||||
@ -1537,6 +1547,22 @@ export function fuzzySearchWorldInfo(data, searchValue) {
|
||||
return results.map(x => x.item?.uid);
|
||||
}
|
||||
|
||||
export function fuzzySearchTags(searchValue) {
|
||||
const fuse = new Fuse(tags, {
|
||||
keys: [
|
||||
{ name: 'name', weight: 1},
|
||||
],
|
||||
includeScore: true,
|
||||
ignoreLocation: true,
|
||||
threshold: 0.2
|
||||
});
|
||||
|
||||
const results = fuse.search(searchValue);
|
||||
console.debug('Tags fuzzy search results for ' + searchValue, results);
|
||||
const ids = results.map(x => String(x.item?.id)).filter(x => x);
|
||||
return ids;
|
||||
}
|
||||
|
||||
export function fuzzySearchGroups(searchValue) {
|
||||
const fuse = new Fuse(groups, {
|
||||
keys: [
|
||||
@ -1664,8 +1690,7 @@ async function saveTheme() {
|
||||
enableLabMode: power_user.enableLabMode,
|
||||
hotswap_enabled: power_user.hotswap_enabled,
|
||||
custom_css: power_user.custom_css,
|
||||
|
||||
|
||||
bogus_folders: power_user.bogus_folders,
|
||||
};
|
||||
|
||||
const response = await fetch('/savetheme', {
|
||||
@ -2790,6 +2815,13 @@ $(document).ready(() => {
|
||||
switchSimpleMode();
|
||||
});
|
||||
|
||||
$('#bogus_folders').on('input', function() {
|
||||
const value = !!$(this).prop('checked');
|
||||
power_user.bogus_folders = value;
|
||||
saveSettingsDebounced();
|
||||
printCharacters(true);
|
||||
});
|
||||
|
||||
$(document).on('click', '#debug_table [data-debug-function]', function () {
|
||||
const functionId = $(this).data('debug-function');
|
||||
const functionRecord = debug_functions.find(f => f.functionId === functionId);
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
menu_type,
|
||||
getCharacters,
|
||||
entitiesFilter,
|
||||
printCharacters,
|
||||
} from "../script.js";
|
||||
import { FILTER_TYPES, FilterHelper } from "./filters.js";
|
||||
|
||||
@ -48,12 +49,12 @@ const InListActionable = {
|
||||
}
|
||||
|
||||
const DEFAULT_TAGS = [
|
||||
{ id: uuidv4(), name: "Plain Text" },
|
||||
{ id: uuidv4(), name: "OpenAI" },
|
||||
{ id: uuidv4(), name: "W++" },
|
||||
{ id: uuidv4(), name: "Boostyle" },
|
||||
{ id: uuidv4(), name: "PList" },
|
||||
{ id: uuidv4(), name: "AliChat" },
|
||||
{ id: uuidv4(), name: "Plain Text", create_date: Date.now() },
|
||||
{ id: uuidv4(), name: "OpenAI", create_date: Date.now() },
|
||||
{ id: uuidv4(), name: "W++", create_date: Date.now() },
|
||||
{ id: uuidv4(), name: "Boostyle", create_date: Date.now() },
|
||||
{ id: uuidv4(), name: "PList", create_date: Date.now() },
|
||||
{ id: uuidv4(), name: "AliChat", create_date: Date.now() },
|
||||
];
|
||||
|
||||
let tags = [];
|
||||
@ -208,8 +209,8 @@ function selectTag(event, ui, listSelector) {
|
||||
const characterIds = characterData ? JSON.parse(characterData).characterIds : null;
|
||||
|
||||
if (characterIds) {
|
||||
characterIds.forEach((characterId) => addTagToMap(tag.id,characterId));
|
||||
} else {
|
||||
characterIds.forEach((characterId) => addTagToMap(tag.id, characterId));
|
||||
} else {
|
||||
addTagToMap(tag.id);
|
||||
}
|
||||
|
||||
@ -232,7 +233,6 @@ function getExistingTags(new_tags) {
|
||||
return existing_tags
|
||||
}
|
||||
|
||||
|
||||
async function importTags(imported_char) {
|
||||
let imported_tags = imported_char.tags.filter(t => t !== "ROOT" && t !== "TAVERN");
|
||||
let existingTags = await getExistingTags(imported_tags);
|
||||
@ -272,13 +272,13 @@ async function importTags(imported_char) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function createNewTag(tagName) {
|
||||
const tag = {
|
||||
id: uuidv4(),
|
||||
name: tagName,
|
||||
color: '',
|
||||
color2: '',
|
||||
create_date: Date.now(),
|
||||
};
|
||||
tags.push(tag);
|
||||
return tag;
|
||||
@ -477,55 +477,78 @@ export function createTagInput(inputSelector, listSelector) {
|
||||
|
||||
function onViewTagsListClick() {
|
||||
$('#dialogue_popup').addClass('large_dialogue_popup');
|
||||
const list = document.createElement('div');
|
||||
const list = $(document.createElement('div'));
|
||||
list.attr('id', 'tag_view_list');
|
||||
const everything = Object.values(tag_map).flat();
|
||||
$(list).append('<h3>Tags</h3><i>Click on the tag name to edit it.</i><br>');
|
||||
$(list).append('<i>Click on color box to assign new color.</i><br><br>');
|
||||
$(list).append(`
|
||||
<div class="title_restorable alignItemsBaseline">
|
||||
<h3>Tag Management</h3>
|
||||
<div class="menu_button menu_button_icon tag_view_create">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
<span data-i18n="Create">Create</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="justifyLeft m-b-1">
|
||||
<small>
|
||||
Click on the tag name to edit it.<br>
|
||||
Click on color box to assign new color.
|
||||
</small>
|
||||
</div>`);
|
||||
|
||||
for (const tag of tags.slice().sort((a, b) => a?.name?.toLowerCase()?.localeCompare(b?.name?.toLowerCase()))) {
|
||||
const count = everything.filter(x => x == tag.id).length;
|
||||
const template = $('#tag_view_template .tag_view_item').clone();
|
||||
template.attr('id', tag.id);
|
||||
template.find('.tag_view_counter_value').text(count);
|
||||
template.find('.tag_view_name').text(tag.name);
|
||||
template.find('.tag_view_name').addClass('tag');
|
||||
|
||||
template.find('.tag_view_name').css('background-color', tag.color);
|
||||
template.find('.tag_view_name').css('color', tag.color2);
|
||||
|
||||
const colorPickerId = tag.id + "-tag-color";
|
||||
const colorPicker2Id = tag.id + "-tag-color2";
|
||||
|
||||
template.find('.tagColorPickerHolder').html(
|
||||
`<toolcool-color-picker id="${colorPickerId}" color="${tag.color}" class="tag-color"></toolcool-color-picker>`
|
||||
);
|
||||
template.find('.tagColorPicker2Holder').html(
|
||||
`<toolcool-color-picker id="${colorPicker2Id}" color="${tag.color2}" class="tag-color2"></toolcool-color-picker>`
|
||||
);
|
||||
|
||||
template.find('.tag-color').attr('id', colorPickerId);
|
||||
template.find('.tag-color2').attr('id', colorPicker2Id);
|
||||
|
||||
list.appendChild(template.get(0));
|
||||
|
||||
setTimeout(function () {
|
||||
document.querySelector(`.tag-color[id="${colorPickerId}"`).addEventListener('change', (evt) => {
|
||||
onTagColorize(evt);
|
||||
});
|
||||
|
||||
}, 100);
|
||||
|
||||
setTimeout(function () {
|
||||
document.querySelector(`.tag-color2[id="${colorPicker2Id}"`).addEventListener('change', (evt) => {
|
||||
onTagColorize2(evt);
|
||||
});
|
||||
}, 100);
|
||||
|
||||
$(colorPickerId).color = tag.color;
|
||||
$(colorPicker2Id).color = tag.color2;
|
||||
|
||||
appendViewTagToList(list, tag, everything);
|
||||
}
|
||||
callPopup(list.outerHTML, 'text');
|
||||
|
||||
callPopup(list, 'text');
|
||||
}
|
||||
|
||||
function onTagCreateClick() {
|
||||
const tag = createNewTag('New Tag');
|
||||
appendViewTagToList($('#tag_view_list'), tag, []);
|
||||
printCharacters(false);
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
function appendViewTagToList(list, tag, everything) {
|
||||
const count = everything.filter(x => x == tag.id).length;
|
||||
const template = $('#tag_view_template .tag_view_item').clone();
|
||||
template.attr('id', tag.id);
|
||||
template.find('.tag_view_counter_value').text(count);
|
||||
template.find('.tag_view_name').text(tag.name);
|
||||
template.find('.tag_view_name').addClass('tag');
|
||||
|
||||
template.find('.tag_view_name').css('background-color', tag.color);
|
||||
template.find('.tag_view_name').css('color', tag.color2);
|
||||
|
||||
const colorPickerId = tag.id + "-tag-color";
|
||||
const colorPicker2Id = tag.id + "-tag-color2";
|
||||
|
||||
template.find('.tagColorPickerHolder').html(
|
||||
`<toolcool-color-picker id="${colorPickerId}" color="${tag.color}" class="tag-color"></toolcool-color-picker>`
|
||||
);
|
||||
template.find('.tagColorPicker2Holder').html(
|
||||
`<toolcool-color-picker id="${colorPicker2Id}" color="${tag.color2}" class="tag-color2"></toolcool-color-picker>`
|
||||
);
|
||||
|
||||
template.find('.tag-color').attr('id', colorPickerId);
|
||||
template.find('.tag-color2').attr('id', colorPicker2Id);
|
||||
|
||||
list.append(template);
|
||||
|
||||
setTimeout(function () {
|
||||
document.querySelector(`.tag-color[id="${colorPickerId}"`).addEventListener('change', (evt) => {
|
||||
onTagColorize(evt);
|
||||
});
|
||||
}, 100);
|
||||
|
||||
setTimeout(function () {
|
||||
document.querySelector(`.tag-color2[id="${colorPicker2Id}"`).addEventListener('change', (evt) => {
|
||||
onTagColorize2(evt);
|
||||
});
|
||||
}, 100);
|
||||
|
||||
$(colorPickerId).color = tag.color;
|
||||
$(colorPicker2Id).color = tag.color2;
|
||||
}
|
||||
|
||||
function onTagDeleteClick() {
|
||||
@ -541,6 +564,7 @@ function onTagDeleteClick() {
|
||||
tags.splice(index, 1);
|
||||
$(`.tag[id="${id}"]`).remove();
|
||||
$(`.tag_view_item[id="${id}"]`).remove();
|
||||
printCharacters(false);
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
@ -559,6 +583,7 @@ function onTagColorize(evt) {
|
||||
const newColor = evt.detail.rgba;
|
||||
$(evt.target).parent().parent().find('.tag_view_name').css('background-color', newColor);
|
||||
$(`.tag[id="${id}"]`).css('background-color', newColor);
|
||||
$(`.bogus_folder_select[tagid="${id}"] .avatar`).css('background-color', newColor);
|
||||
const tag = tags.find(x => x.id === id);
|
||||
tag.color = newColor;
|
||||
console.debug(tag);
|
||||
@ -571,6 +596,7 @@ function onTagColorize2(evt) {
|
||||
const newColor = evt.detail.rgba;
|
||||
$(evt.target).parent().parent().find('.tag_view_name').css('color', newColor);
|
||||
$(`.tag[id="${id}"]`).css('color', newColor);
|
||||
$(`.bogus_folder_select[tagid="${id}"] .avatar`).css('color', newColor);
|
||||
const tag = tags.find(x => x.id === id);
|
||||
tag.color2 = newColor;
|
||||
console.debug(tag);
|
||||
@ -597,4 +623,5 @@ $(document).ready(() => {
|
||||
$(document).on("click", ".tags_view", onViewTagsListClick);
|
||||
$(document).on("click", ".tag_delete", onTagDeleteClick);
|
||||
$(document).on("input", ".tag_view_name", onTagRenameInput);
|
||||
$(document).on("click", ".tag_view_create", onTagCreateClick);
|
||||
});
|
||||
|
@ -550,7 +550,7 @@ export function timestampToMoment(timestamp) {
|
||||
return moment.invalid();
|
||||
}
|
||||
|
||||
// Unix time (legacy TAI)
|
||||
// Unix time (legacy TAI / tags)
|
||||
if (typeof timestamp === 'number') {
|
||||
return moment(timestamp);
|
||||
}
|
||||
|
Reference in New Issue
Block a user