Merge branch 'staging' into parser-followup-2

This commit is contained in:
LenAnderson 2024-07-17 17:43:49 -04:00
commit 8a55d64158
10 changed files with 91 additions and 18 deletions

View File

@ -17,6 +17,15 @@ module.exports = {
node: true,
},
},
{
files: ['src/**/*.mjs'],
parserOptions: {
sourceType: 'module',
},
env: {
node: true,
},
},
{
// Browser-side files
files: ['public/**/*.js'],

View File

@ -2264,6 +2264,7 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
if (type === 'swipe') {
const swipeMessage = chatElement.find(`[mesid="${chat.length - 1}"]`);
swipeMessage.attr('swipeid', params.swipeId);
swipeMessage.find('.mes_text').html(messageText).attr('title', title);
swipeMessage.find('.timestamp').text(timestamp).attr('title', `${params.extra.api} - ${params.extra.model}`);
appendMediaToMessage(mes, swipeMessage);
@ -4182,6 +4183,8 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
summarizeString: (extension_prompts['1_memory']?.value || ''),
authorsNoteString: (extension_prompts['2_floating_prompt']?.value || ''),
smartContextString: (extension_prompts['chromadb']?.value || ''),
chatVectorsString: (extension_prompts['3_vectors']?.value || ''),
dataBankVectorsString: (extension_prompts['4_vectors_data_bank']?.value || ''),
worldInfoString: worldInfoString,
storyString: storyString,
beforeScenarioAnchor: beforeScenarioAnchor,
@ -4813,6 +4816,8 @@ export async function itemizedParams(itemizedPrompts, thisPromptSet) {
thisPrompt_padding: itemizedPrompts[thisPromptSet].padding,
this_main_api: itemizedPrompts[thisPromptSet].main_api,
chatInjects: await getTokenCountAsync(itemizedPrompts[thisPromptSet].chatInjects),
chatVectorsStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].chatVectorsString),
dataBankVectorsStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].dataBankVectorsString),
};
if (params.chatInjects) {

View File

@ -72,7 +72,7 @@ const registerPromptManagerMigration = () => {
* Represents a prompt.
*/
class Prompt {
identifier; role; content; name; system_prompt; position; injection_position; injection_depth; forbid_overrides;
identifier; role; content; name; system_prompt; position; injection_position; injection_depth; forbid_overrides; extension;
/**
* Create a new Prompt instance.
@ -87,8 +87,9 @@ class Prompt {
* @param {number} param0.injection_position - The insert position of the prompt.
* @param {number} param0.injection_depth - The depth of the prompt in the chat.
* @param {boolean} param0.forbid_overrides - Indicates if the prompt should not be overridden.
* @param {boolean} param0.extension - Prompt is added by an extension.
*/
constructor({ identifier, role, content, name, system_prompt, position, injection_depth, injection_position, forbid_overrides } = {}) {
constructor({ identifier, role, content, name, system_prompt, position, injection_depth, injection_position, forbid_overrides, extension } = {}) {
this.identifier = identifier;
this.role = role;
this.content = content;
@ -98,6 +99,7 @@ class Prompt {
this.injection_depth = injection_depth;
this.injection_position = injection_position;
this.forbid_overrides = forbid_overrides;
this.extension = extension ?? false;
}
}

View File

@ -23,8 +23,7 @@ import { debounce_timeout } from '../../constants.js';
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 { resolveVariable } from '../../variables.js';
import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
import { MacrosParser } from '../../macros.js';
export { MODULE_NAME };
const MODULE_NAME = '1_memory';
@ -937,4 +936,6 @@ jQuery(async function () {
helpString: 'Summarizes the given text. If no text is provided, the current chat will be summarized. Can specify the source and the prompt to use.',
returns: ARGUMENT_TYPE.STRING,
}));
MacrosParser.registerMacro('summary', () => getLatestMemoryFromChat(getContext().chat));
});

View File

@ -1082,6 +1082,11 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm
}
}
// Other relative extension prompts
for (const prompt of prompts.collection.filter(p => p.extension && p.position)) {
chatCompletion.insert(Message.fromPrompt(prompt), 'main', prompt.position);
}
// Add in-chat injections
messages = populationInjectionPrompts(userAbsolutePrompts, messages);
@ -1187,6 +1192,35 @@ function preparePromptsForChatCompletion({ Scenario, charPersonality, name2, wor
systemPrompts.push({ role: 'system', content: power_user.persona_description, identifier: 'personaDescription' });
}
const knownExtensionPrompts = [
'1_memory',
'2_floating_prompt',
'3_vectors',
'4_vectors_data_bank',
'chromadb',
'PERSONA_DESCRIPTION',
'QUIET_PROMPT',
'DEPTH_PROMPT',
];
// Anything that is not a known extension prompt
for (const key in extensionPrompts) {
if (Object.hasOwn(extensionPrompts, key)) {
const prompt = extensionPrompts[key];
if (knownExtensionPrompts.includes(key)) continue;
if (!extensionPrompts[key].value) continue;
if (![extension_prompt_types.BEFORE_PROMPT, extension_prompt_types.IN_PROMPT].includes(prompt.position)) continue;
systemPrompts.push({
identifier: key.replace(/\W/g, '_'),
position: getPromptPosition(prompt.position),
role: getPromptRole(prompt.role),
content: prompt.value,
extension: true,
});
}
}
// This is the prompt order defined by the user
const prompts = promptManager.getPromptCollection();

View File

@ -1,8 +1,8 @@
<h3 class="flex-container justifyCenter alignitemscenter">
Prompt Itemization
<div id="showRawPrompt" class="fa-solid fa-square-poll-horizontal menu_button"></div>
<div id="copyPromptToClipboard" class="fa-solid fa-copy menu_button"></div>
<div id="diffPrevPrompt" class="fa-solid fa-code-compare menu_button"></div>
<div id="showRawPrompt" class="fa-solid fa-square-poll-horizontal menu_button" title="Show Raw Prompt" data-i18n="[title]Show Raw Prompt"></div>
<div id="copyPromptToClipboard" class="fa-solid fa-copy menu_button" title="Copy Prompt" data-i18n="[title]Copy Prompt"></div>
<div id="diffPrevPrompt" class="fa-solid fa-code-compare menu_button" title="Show Prompt Differences" data-i18n="[title]Show Prompt Differences"></div>
</h3>
Tokenizer: {{selectedTokenizer}}<br>
API Used: {{this_main_api}}<br>
@ -107,6 +107,14 @@ API Used: {{this_main_api}}<br>
<div class=" flex1 tokenItemizingSubclass">-- Smart Context:</div>
<div class="tokenItemizingSubclass"> {{smartContextStringTokens}}</div>
</div>
<div class="flex-container ">
<div class=" flex1 tokenItemizingSubclass">-- Vector Storage (Chats):</div>
<div class="tokenItemizingSubclass"> {{chatVectorsStringTokens}}</div>
</div>
<div class="flex-container ">
<div class=" flex1 tokenItemizingSubclass">-- Vector Storage (Data Bank):</div>
<div class="tokenItemizingSubclass"> {{dataBankVectorsStringTokens}}</div>
</div>
</div>
<div class="wide100p flex-container">
<div class="flex1" style="color: mediumpurple;">&lcub;&lcub;&rcub;&rcub; Bias:</div>

View File

@ -1,8 +1,8 @@
<h3 class="flex-container justifyCenter alignitemscenter">
Prompt Itemization
<div id="showRawPrompt" class="fa-solid fa-square-poll-horizontal menu_button"></div>
<div id="copyPromptToClipboard" class="fa-solid fa-copy menu_button"></div>
<div id="diffPrevPrompt" class="fa-solid fa-code-compare menu_button"></div>
<div id="showRawPrompt" class="fa-solid fa-square-poll-horizontal menu_button" title="Show Raw Prompt" data-i18n="[title]Show Raw Prompt"></div>
<div id="copyPromptToClipboard" class="fa-solid fa-copy menu_button" title="Copy Prompt" data-i18n="[title]Copy Prompt"></div>
<div id="diffPrevPrompt" class="fa-solid fa-code-compare menu_button" title="Show Prompt Differences" data-i18n="[title]Show Prompt Differences"></div>
</h3>
Tokenizer: {{selectedTokenizer}}<br>
API Used: {{this_main_api}}<br>
@ -79,6 +79,14 @@ API Used: {{this_main_api}}<br>
<div class=" flex1 tokenItemizingSubclass">-- Smart Context:</div>
<div class="tokenItemizingSubclass"> {{smartContextStringTokens}}</div>
</div>
<div class="flex-container ">
<div class=" flex1 tokenItemizingSubclass">-- Vector Storage (Chats):</div>
<div class="tokenItemizingSubclass"> {{chatVectorsStringTokens}}</div>
</div>
<div class="flex-container ">
<div class=" flex1 tokenItemizingSubclass">-- Vector Storage (Data Bank):</div>
<div class="tokenItemizingSubclass"> {{dataBankVectorsStringTokens}}</div>
</div>
</div>
<div class="wide100p flex-container">
<div class="flex1" style="color: mediumpurple;">&lcub;&lcub;&rcub;&rcub; Bias:</div>

View File

@ -16,6 +16,7 @@
<li><tt>&lcub;&lcub;persona&rcub;&rcub;</tt> <span data-i18n="help_macros_12">your current Persona Description</span></li>
<li><tt>&lcub;&lcub;mesExamples&rcub;&rcub;</tt> <span data-i18n="help_macros_13">the Character's Dialogue Examples</span></li>
<li><tt>&lcub;&lcub;mesExamplesRaw&rcub;&rcub;</tt> <span data-i18n="help_macros_14">unformatted Dialogue Examples </span><b data-i18n="(only for Story String)">(only for Story String)</b></li>
<li><tt>&lcub;&lcub;summary&rcub;&rcub;</tt> <span data-i18n="help_macros_summary">the latest chat summary generated by the "Summarize" extension (if available).</span></li>
<li><tt>&lcub;&lcub;user&rcub;&rcub;</tt> <span data-i18n="help_macros_15">your current Persona username</span></li>
<li><tt>&lcub;&lcub;char&rcub;&rcub;</tt> <span data-i18n="help_macros_16">the Character's name</span></li>
<li><tt>&lcub;&lcub;char_version&rcub;&rcub;</tt> <span data-i18n="help_macros_17">the Character's version number</span></li>

View File

@ -16,7 +16,10 @@ const STATS_FILE = 'stats.json';
* @type {Map<string, Object>} The stats object for each user.
*/
const STATS = new Map();
let lastSaveTimestamp = 0;
/**
* @type {Map<string, number>} The timestamps for each user.
*/
const TIMESTAMPS = new Map();
/**
* Convert a timestamp to an integer timestamp.
@ -119,7 +122,6 @@ function timestampToMoment(timestamp) {
* @returns {Promise<Object>} The aggregated stats object.
*/
async function collectAndCreateStats(chatsPath, charactersPath) {
console.log('Collecting and creating stats...');
const files = await readdir(charactersPath);
const pngFiles = files.filter((file) => file.endsWith('.png'));
@ -145,10 +147,10 @@ async function collectAndCreateStats(chatsPath, charactersPath) {
* @param {string} charactersPath Path to the directory containing the character files.
*/
async function recreateStats(handle, chatsPath, charactersPath) {
console.log('Collecting and creating stats for user:', handle);
const stats = await collectAndCreateStats(chatsPath, charactersPath);
STATS.set(handle, stats);
await saveStatsToFile();
console.debug('Stats (re)created and saved to file.');
}
/**
@ -167,7 +169,7 @@ async function init() {
} catch (err) {
// If the file doesn't exist or is invalid, initialize stats
if (err.code === 'ENOENT' || err instanceof SyntaxError) {
recreateStats(handle, directories.chats, directories.characters);
await recreateStats(handle, directories.chats, directories.characters);
} else {
throw err; // Rethrow the error if it's something we didn't expect
}
@ -185,13 +187,17 @@ async function init() {
async function saveStatsToFile() {
const userHandles = await getAllUserHandles();
for (const handle of userHandles) {
const charStats = STATS.get(handle) || {};
if (!STATS.has(handle)) {
continue;
}
const charStats = STATS.get(handle);
const lastSaveTimestamp = TIMESTAMPS.get(handle) || 0;
if (charStats.timestamp > lastSaveTimestamp) {
try {
const directories = getUserDirectories(handle);
const statsFilePath = path.join(directories.root, STATS_FILE);
await writeFileAtomic(statsFilePath, JSON.stringify(charStats));
lastSaveTimestamp = Date.now();
TIMESTAMPS.set(handle, Date.now());
} catch (error) {
console.log('Failed to save stats to file.', error);
}

View File

@ -1,7 +1,6 @@
import { pipeline, env, RawImage, Pipeline } from 'sillytavern-transformers';
import { getConfigValue } from './util.js';
import path from 'path';
import _ from 'lodash';
configureTransformers();
@ -114,4 +113,4 @@ async function getPipeline(task, forceModel = '') {
export default {
getPipeline,
getRawImage,
}
};