diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 614d2e5f2..2dd35f857 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -30,6 +30,7 @@ Providing the logs from the browser DevTools console (opened by pressing the F12 **Desktop (please complete the following information):** - OS/Device: [e.g. Windows 11] - Environment: [cloud, local] + - Node.js version (if applicable): [run `node --version` in cmd] - Browser [e.g. chrome, safari] - Generation API [e.g. KoboldAI, OpenAI] - Branch [main, dev] diff --git a/package-lock.json b/package-lock.json index af472b031..94ce9514b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { "name": "sillytavern", - "version": "1.5.1", + "version": "1.5.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sillytavern", - "version": "1.5.1", + "version": "1.5.3", "license": "AGPL-3.0", "dependencies": { "@dqbd/tiktoken": "^1.0.2", + "@zeldafan0225/ai_horde": "^4.0.1", "axios": "^1.3.4", "command-exists": "^1.2.9", "compression": "^1", @@ -34,6 +35,7 @@ "png-chunks-extract": "^1.0.0", "rimraf": "^3.0.2", "sanitize-filename": "^1.6.3", + "uniqolor": "^1.1.0", "webp-converter": "2.3.2", "ws": "^8.13.0", "yargs": "^17.7.1" @@ -417,6 +419,11 @@ "regenerator-runtime": "^0.13.3" } }, + "node_modules/@thunder04/supermap": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@thunder04/supermap/-/supermap-3.0.2.tgz", + "integrity": "sha512-SjlUrfe45mwiAgKZHRRhh+oHRwXsjrCg6NI2HJxymTJt+9SwJw422yse/A5lr5WBpTky6qEce+H6Ec1sytm93A==" + }, "node_modules/@tokenizer/token": { "version": "0.3.0", "license": "MIT" @@ -433,6 +440,16 @@ "node": ">=10.0.0" } }, + "node_modules/@zeldafan0225/ai_horde": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@zeldafan0225/ai_horde/-/ai_horde-4.0.1.tgz", + "integrity": "sha512-mf1cknnBYzKCvgH4KAkdVY3J7sLkR2b79W6I9ZEA2aJCyua28bpZzNaCDSHKKyaNj+0wyHViC+L53X32jw9pMg==", + "dependencies": { + "@thunder04/supermap": "^3.0.2", + "centra": "^2.5.0", + "esbuild": "^0.12.28" + } + }, "node_modules/accepts": { "version": "1.3.8", "license": "MIT", @@ -620,6 +637,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/centra": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/centra/-/centra-2.6.0.tgz", + "integrity": "sha512-dgh+YleemrT8u85QL11Z6tYhegAs3MMxsaWAq/oXeAmYJ7VxL3SI9TZtnfaEvNDMAPolj25FXIb3S+HCI4wQaQ==" + }, "node_modules/cliui": { "version": "8.0.1", "license": "ISC", @@ -871,6 +893,15 @@ "node": ">= 0.8" } }, + "node_modules/esbuild": { + "version": "0.12.29", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.29.tgz", + "integrity": "sha512-w/XuoBCSwepyiZtIRsKsetiLDUVGPVw1E/R3VTFSecIy8UR7Cq3SOtwKHJMFoVqqVG36aGkzh4e8BvpO1Fdc7g==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + } + }, "node_modules/escalade": { "version": "3.1.1", "license": "MIT", @@ -1935,6 +1966,11 @@ "version": "0.0.6", "license": "MIT" }, + "node_modules/uniqolor": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/uniqolor/-/uniqolor-1.1.0.tgz", + "integrity": "sha512-j2XyokF24fsj+L5u6fbu4rM3RQc6VWJuAngYM2k0ZdG3yiVxt0smLkps2GmQIYqK8VkELGdM9vFU/HfOkK/zoQ==" + }, "node_modules/unpipe": { "version": "1.0.0", "license": "MIT", diff --git a/package.json b/package.json index b46c5a721..30bf2571b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "dependencies": { "@dqbd/tiktoken": "^1.0.2", + "@zeldafan0225/ai_horde": "^4.0.1", "axios": "^1.3.4", "command-exists": "^1.2.9", "compression": "^1", @@ -25,6 +26,7 @@ "png-chunks-extract": "^1.0.0", "rimraf": "^3.0.2", "sanitize-filename": "^1.6.3", + "uniqolor": "^1.1.0", "webp-converter": "2.3.2", "ws": "^8.13.0", "yargs": "^17.7.1" @@ -40,7 +42,7 @@ "type": "git", "url": "https://github.com/Cohee1207/SillyTavern.git" }, - "version": "1.5.1", + "version": "1.5.3", "scripts": { "start": "node server.js" }, diff --git a/public/TextGen Settings/LLaMa-Precise.settings b/public/TextGen Settings/LLaMa-Precise.settings new file mode 100644 index 000000000..1eedb3d74 --- /dev/null +++ b/public/TextGen Settings/LLaMa-Precise.settings @@ -0,0 +1,15 @@ +{ + "temp": 0.7, + "top_p": 0.1, + "top_k": 40, + "typical_p": 1, + "rep_pen": 1.18, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 200, + "encoder_rep_pen": 1, + "do_sample": true, + "early_stopping": false +} \ No newline at end of file diff --git a/public/index.html b/public/index.html index b9214dd96..67f960f47 100644 --- a/public/index.html +++ b/public/index.html @@ -366,6 +366,15 @@ +
+ +
+ Display a breakdown of the tokens used in the request. +
+
Context Size (tokens) @@ -1176,7 +1185,7 @@
-
+

Advanced Formatting @@ -1207,6 +1216,15 @@ Disable chat start formatting + + +

Custom Chat Separator @@ -1346,24 +1364,22 @@

-
+ @@ -1373,12 +1389,20 @@
-
+
-
+
+
+
+ + +

- World Info + World Selector ? @@ -1440,6 +1464,41 @@

+ +
+
+
+ +
+ +
+ +

+ World Info Editor + ? +

+
+ + + +
+ + +
+
+
+ +
+
+ +
+ + + + +
+ +

Soft Prompt

@@ -1663,6 +1722,10 @@ Auto-scroll Chat +
+
+
+ Current Members +
+
+
+
+
+
+
+
Add Members @@ -1954,17 +2028,6 @@
-
-
- Current Members -
-
-
-
-
-
-
-
@@ -2036,7 +2099,7 @@
-

- Advanced Defininitions +

- Advanced Definitions
@@ -2061,7 +2124,7 @@

Talkativeness

-
How often the chracter speaks in  group chats! +
How often the character speaks in  group chats!
@@ -2081,38 +2144,7 @@
-
-
-
-
- -
- -

- World Info Editor - ? -

-
- - -
 
-
- - -
-
-
-
-
- -
- -   - - -
-
@@ -2191,6 +2223,7 @@
+
@@ -2200,14 +2233,14 @@
@@ -2341,6 +2374,7 @@ ${characterName}
+
@@ -2436,6 +2470,11 @@
+
@@ -2445,7 +2484,7 @@
-
+
@@ -2502,6 +2541,9 @@
+
+
+
\ No newline at end of file diff --git a/public/notes/content.md b/public/notes/content.md index edbf848d2..f0920c276 100644 --- a/public/notes/content.md +++ b/public/notes/content.md @@ -393,26 +393,9 @@ _Lost API keys can't be restored! Make sure to keep it safe!_ ## Anchors -Anchors are used to increase the length of messages. -There are two types of anchors: _Character Anchor_ and _Style Anchor_. +This feature is considered obsolete and has been removed. -_Character Anchor_ - affects the character played by the AI by motivating it to write longer messages. - -Looks like: `[Elaborate speaker]` - -_Style Anchor_ - affects the entire AI model, motivating the AI to write longer messages even when it is not acting as the character. - -Looks like: `[Writing style: very long messages]` - -*** - -Anchors Order sets the location of anchors in the prompt, the first anchor in the order is much further back in the context and thus has less influence than second. - -The second anchor is only turned on after 8-12 messages, because when the chat still only has a few messages, the first anchor creates enough effect on its own. - -Sometimes an AI model may not perceive anchors correctly or the AI model already generates sufficiently long messages. For these cases, you can disable the anchors by unchecking their respective boxes. - -_When using Pygmalion models these anchors are automatically disabled, since Pygmalion already generates long enough messages._ +The use of the Author's Note extension is now a preferred way to add prompt injections of variable depth. ## Instruct Mode @@ -594,6 +577,8 @@ Characters are drafted based on the order they are presented in group members li ## Multigen +*This feature provides a pseudo-streaming functionality which conflicts with token streaming. When Multigen is enabled and generation API supports streaming, only Multigen streaming will be used.* + SillyTavern tries to create faster and longer responses by chaining the generation using smaller batches. ### Default settings: @@ -614,6 +599,7 @@ Next batches = 30 tokens 2. Character starts speaking for You. 3. <|endoftext|> token reached. 4. No text generated. +5. Stop sequence generated. (Instruct mode only) ## User Settings diff --git a/public/script.js b/public/script.js index f1b3dac95..b12546cee 100644 --- a/public/script.js +++ b/public/script.js @@ -106,7 +106,7 @@ import { setPoeOnlineStatus, } from "./scripts/poe.js"; -import { debounce, delay, restoreCaretPosition, saveCaretPosition } from "./scripts/utils.js"; +import { debounce, delay, restoreCaretPosition, saveCaretPosition, end_trim_to_sentence } from "./scripts/utils.js"; import { extension_settings, getContext, loadExtensionSettings } from "./scripts/extensions.js"; import { executeSlashCommands, getSlashCommandsHelp, registerSlashCommand } from "./scripts/slash-commands.js"; import { @@ -125,6 +125,7 @@ import { secret_state, writeSecret } from "./scripts/secrets.js"; +import uniqolor from "./scripts/uniqolor.js"; //exporting functions and vars for mods export { @@ -204,6 +205,7 @@ let converter; reloadMarkdownProcessor(); // array for prompt token calculations +console.log('initializing Prompt Itemization Array on Startup'); let itemizedPrompts = []; /* let bg_menu_toggle = false; */ @@ -244,6 +246,9 @@ let optionsPopper = Popper.createPopper(document.getElementById('send_form'), do let exportPopper = Popper.createPopper(document.getElementById('export_button'), document.getElementById('export_format_popup'), { placement: 'left' }); +let rawPromptPopper = Popper.createPopper(document.getElementById('dialogue_popup'), document.getElementById('rawPromptPopup'), { + placement: 'right' +}); let dialogueResolve = null; let chat_metadata = {}; @@ -406,18 +411,21 @@ async function getClientVersion() { } } -function getTokenCount(str, padding = 0) { +function getTokenCount(str, padding = undefined) { let tokenizerType = power_user.tokenizer; if (main_api === 'openai') { - // For main prompt building - if (padding == power_user.token_padding) { + if (padding === power_user.token_padding) { + // For main "shadow" prompt building tokenizerType = tokenizers.NONE; - // For extensions and WI } else { + // For extensions and WI return getTokenCountOpenAI(str); } + } + if (padding === undefined) { + padding = 0; } switch (tokenizerType) { @@ -531,10 +539,6 @@ var message_already_generated = ""; var cycle_count_generation = 0; var swipes = true; - -let anchor_order = 0; -let style_anchor = true; -let character_anchor = true; let extension_prompts = {}; var main_api;// = "kobold"; @@ -1129,28 +1133,34 @@ function addOneMessage(mes, { type = "normal", insertAfter = null, scroll = true if (isSystem) { newMessage.find(".mes_edit").hide(); - newMessage.find(".mes_prompt").hide(); //dont'd need prompt display for sys messages + newMessage.find(".mes_prompt").hide(); //don't need prompt button for sys } - // don't need prompt butons for user messages + // don't need prompt button for user if (params.isUser === true) { newMessage.find(".mes_prompt").hide(); + console.log(`hiding prompt for user mesID ${params.mesId}`); } //shows or hides the Prompt display button let mesIdToFind = Number(newMessage.attr('mesId')); if (itemizedPrompts.length !== 0) { + //console.log(`itemizedPrompt.length = ${itemizedPrompts.length}`) for (var i = 0; i < itemizedPrompts.length; i++) { if (itemizedPrompts[i].mesId === mesIdToFind) { newMessage.find(".mes_prompt").show(); + console.log(`showing prompt for mesID ${params.mesId} from ${params.characterName}`); } else { - console.log('no cache found for mesID, hiding prompt button and continuing search'); + console.log(`no cache obj for mesID ${mesIdToFind}, hiding prompt button and continuing search`); newMessage.find(".mes_prompt").hide(); + console.log(itemizedPrompts); } } - } else { //hide all when prompt cache is empty + } else if (params.isUser !== true) { //hide all when prompt cache is empty + console.log('saw empty prompt cache, hiding all prompt buttons'); $(".mes_prompt").hide(); - } + //console.log(itemizedPrompts); + } else { console.log('skipping prompt data for User Message'); } newMessage.find('.avatar img').on('error', function () { $(this).hide(); @@ -1250,15 +1260,16 @@ function getStoppingStrings(isImpersonate, addSpace) { } } + // Cohee: oobabooga's textgen always appends newline before the sequence as a stopping string + // But it's a problem for Metharme which doesn't use newlines to separate them. + const wrap = (s) => power_user.instruct.wrap ? '\n' + s : s; + if (power_user.instruct.enabled) { - // Cohee: This was borrowed from oobabooga's textgen. But.. - // What if a model doesn't use newlines to chain sequences? - // Who knows. if (power_user.instruct.input_sequence) { - result.push(`\n${power_user.instruct.input_sequence}`); + result.push(wrap(power_user.instruct.input_sequence)); } if (power_user.instruct.output_sequence) { - result.push(`\n${power_user.instruct.output_sequence}`); + result.push(wrap(power_user.instruct.output_sequence)); } } @@ -1466,10 +1477,10 @@ class StreamingProcessor { return text; } - onProgressStreaming(messageId, text) { + onProgressStreaming(messageId, text, isFinal) { const isImpersonate = this.type == "impersonate"; text = this.removePrefix(text); - let processedText = cleanUpMessage(text, isImpersonate); + let processedText = cleanUpMessage(text, isImpersonate, !isFinal); let result = extractNameFromMessage(processedText, this.force_name2, isImpersonate); let isName = result.this_mes_is_name; processedText = result.getMessage; @@ -1506,7 +1517,7 @@ class StreamingProcessor { onFinishStreaming(messageId, text) { this.hideStopButton(this.messageId); - this.onProgressStreaming(messageId, text); + this.onProgressStreaming(messageId, text, true); addCopyToCodeBlocks($(`#chat .mes[mesid="${messageId}"]`)); saveChatConditional(); activateSendButtons(); @@ -1626,6 +1637,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, const isImpersonate = type == "impersonate"; const isInstruct = power_user.instruct.enabled; + message_already_generated = isImpersonate ? `${name1}: ` : `${name2}: `; // Name for the multigen prefix const magName = isImpersonate ? (is_pygmalion ? 'You' : name1) : name2; @@ -1635,6 +1647,9 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, message_already_generated = `${magName}: `; } + // To trim after multigen ended + const magFirst = message_already_generated; + const interruptedByCommand = processCommands($("#send_textarea").val(), type); if (interruptedByCommand) { @@ -1661,6 +1676,14 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, hideSwipeButtons(); } + // Set empty promise resolution functions + if (typeof resolve !== 'function') { + resolve = () => { }; + } + if (typeof reject !== 'function') { + reject = () => { }; + } + if (selected_group && !is_group_generating) { generateGroupWrapper(false, type, { resolve, reject, quiet_prompt, force_chid }); return; @@ -1704,47 +1727,13 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, // bias from the latest message is top priority// promptBias = messageBias ?? promptBias ?? ''; - // Compute anchors - const topAnchorDepth = 8; - const bottomAnchorThreshold = 8; - let anchorTop = ''; - let anchorBottom = ''; - if (!is_pygmalion) { - let postAnchorChar = character_anchor ? name2 + " Elaborate speaker" : ""; - let postAnchorStyle = style_anchor ? "Writing style: very long messages" : ""; - if (anchor_order === 0) { - anchorTop = postAnchorChar; - anchorBottom = postAnchorStyle; - } else { // anchor_order === 1 - anchorTop = postAnchorStyle; - anchorBottom = postAnchorChar; - } - - if (anchorBottom) { - anchorBottom = "[" + anchorBottom + "]"; - } - } - //********************************* //PRE FORMATING STRING //********************************* //for normal messages sent from user.. if (textareaText != "" && !automatic_trigger && type !== 'quiet') { - chat[chat.length] = {}; - chat[chat.length - 1]['name'] = name1; - chat[chat.length - 1]['is_user'] = true; - chat[chat.length - 1]['is_name'] = true; - chat[chat.length - 1]['send_date'] = humanizedDateTime(); - chat[chat.length - 1]['mes'] = textareaText; - chat[chat.length - 1]['extra'] = {}; - - if (messageBias) { - console.log('checking bias'); - chat[chat.length - 1]['extra']['bias'] = messageBias; - } - //console.log('Generate calls addOneMessage'); - addOneMessage(chat[chat.length - 1]); + sendMessageAsUser(textareaText, messageBias); } //////////////////////////////////// const scenarioText = chat_metadata['scenario'] || characters[this_chid].scenario; @@ -1780,6 +1769,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, console.log(`Core/all messages: ${coreChat.length}/${chat.length}`); if (main_api === 'openai') { + message_already_generated = ''; // OpenAI doesn't have multigen setOpenAIMessages(coreChat, quiet_prompt); setOpenAIMessageExamples(mesExamplesArray); } @@ -1792,11 +1782,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, storyString += appendToStoryString(Scenario, power_user.disable_scenario_formatting ? '' : 'Scenario: '); } else { storyString += appendToStoryString(charDescription, ''); - - if (coreChat.length < topAnchorDepth) { - storyString += appendToStoryString(charPersonality, power_user.disable_personality_formatting ? '' : name2 + "'s personality: "); - } - + storyString += appendToStoryString(charPersonality, power_user.disable_personality_formatting ? '' : name2 + "'s personality: "); storyString += appendToStoryString(Scenario, power_user.disable_scenario_formatting ? '' : 'Circumstances and context of the dialogue: '); } @@ -1830,7 +1816,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, } else { this_mes_ch_name = charName; } - if (coreChat[j]['is_name']) { + if (coreChat[j]['is_name'] || selected_group) { chat2[i] = this_mes_ch_name + ': ' + coreChat[j]['mes'] + '\n'; } else { chat2[i] = coreChat[j]['mes'] + '\n'; @@ -1846,28 +1832,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, //chat2 = chat2.reverse(); // Determine token limit - let this_max_context = 1487; - if (main_api == 'kobold' || main_api == 'textgenerationwebui') { - this_max_context = (max_context - amount_gen); - } - if (main_api == 'novel') { - if (novel_tier === 1) { - this_max_context = 1024; - } else { - this_max_context = 2048 - 60;//fix for fat tokens - if (nai_settings.model_novel == 'krake-v2') { - this_max_context -= 160; - } - } - } - if (main_api == 'openai') { - this_max_context = oai_settings.openai_max_context; - } - if (main_api == 'poe') { - this_max_context = Number(max_context); - } - - + let this_max_context = getMaxContextSize(); // Adjust token limit for Horde let adjustedParams; @@ -1905,9 +1870,6 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, storyString, examplesString, chatString, - anchorTop, - anchorBottom, - charPersonality, promptBias, allAnchors, quiet_prompt, @@ -1969,7 +1931,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, generatedPromtCache += cycleGenerationPromt; if (generatedPromtCache.length == 0) { if (main_api === 'openai') { - generateOpenAIPromptCache(charPersonality, topAnchorDepth, anchorTop, bottomAnchorThreshold, anchorBottom); + generateOpenAIPromptCache(); } console.log('generating prompt'); @@ -1992,21 +1954,6 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, //item = item.substr(0, item.length - 1); } } - if (i === arrMes.length - topAnchorDepth && !is_pygmalion) { - //chatString = chatString.substr(0,chatString.length-1); - //anchorAndPersonality = "[Genre: roleplay chat][Tone: very long messages with descriptions]"; - let personalityAndAnchor = [charPersonality, anchorTop].filter(x => x).join(' '); - if (personalityAndAnchor) { - item += "[" + personalityAndAnchor + "]\n"; - } - } - if (i === arrMes.length - 1 && coreChat.length > bottomAnchorThreshold && item.trim().startsWith(name1 + ":") && !is_pygmalion) {//For add anchor in end - //chatString+=postAnchor+"\n";//"[Writing style: very long messages]\n"; - if (anchorBottom) { - item = item.replace(/\n$/, " "); - item += anchorBottom + "\n"; - } - } if (is_pygmalion && !isInstruct) { if (i === arrMes.length - 1 && item.trim().startsWith(name1 + ":")) {//for add name2 when user sent item = item + name2 + ":"; @@ -2094,9 +2041,6 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, storyString, mesExmString, mesSendString, - anchorTop, - anchorBottom, - charPersonality, generatedPromtCache, promptBias, allAnchors, @@ -2127,22 +2071,8 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, } // add a custom dingus (if defined) - if (power_user.custom_chat_separator && power_user.custom_chat_separator.length) { - mesSendString = power_user.custom_chat_separator + '\n' + mesSendString; - } - // if chat start formatting is disabled - else if (power_user.disable_start_formatting) { - mesSendString = mesSendString; - } - // add non-pygma dingus - else if (!is_pygmalion) { - mesSendString = '\nThen the roleplay chat between ' + name1 + ' and ' + name2 + ' begins.\n' + mesSendString; - } - // add pygma - else { - mesSendString = '\n' + mesSendString; - //mesSendString = mesSendString; //This edit simply removes the first "" that is prepended to all context prompts - } + mesSendString = adjustChatsSeparator(mesSendString); + let finalPromt = worldInfoBefore + storyString + @@ -2153,50 +2083,17 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, generatedPromtCache + promptBias; - //set array object for prompt token itemization of this message - let thisPromptBits = { - mesId: count_view_mes, - worldInfoBefore: worldInfoBefore, - allAnchors: allAnchors, - summarizeString: (extension_prompts['1_memory']?.value || ''), - authorsNoteString: (extension_prompts['2_floating_prompt']?.value || ''), - worldInfoString: worldInfoString, - storyString: storyString, - worldInfoAfter: worldInfoAfter, - afterScenarioAnchor: afterScenarioAnchor, - examplesString: examplesString, - mesSendString: mesSendString, - generatedPromtCache: generatedPromtCache, - promptBias: promptBias, - finalPromt: finalPromt, - charDescription: charDescription, - charPersonality: charPersonality, - scenarioText: scenarioText, - promptBias: promptBias, - storyString: storyString, - this_max_context: this_max_context, - padding: power_user.token_padding - } - - itemizedPrompts.push(thisPromptBits); - if (zeroDepthAnchor && zeroDepthAnchor.length) { if (!isMultigenEnabled() || tokens_already_generated == 0) { - const trimBothEnds = !force_name2 && !is_pygmalion; - let trimmedPrompt = (trimBothEnds ? zeroDepthAnchor.trim() : zeroDepthAnchor.trimEnd()); - - if (trimBothEnds && !finalPromt.endsWith('\n')) { - finalPromt += '\n'; - } - - finalPromt += trimmedPrompt; - - if (force_name2 || is_pygmalion) { - finalPromt += ' '; - } + finalPromt = appendZeroDepthAnchor(force_name2, zeroDepthAnchor, finalPromt); } } + // Add quiet generation prompt at depth 0 + if (quiet_prompt && quiet_prompt.length) { + finalPromt += `\n${quiet_prompt}`; + } + finalPromt = finalPromt.replace(/\r/gm, ''); if (power_user.collapse_newlines) { @@ -2207,31 +2104,11 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, if (isMultigenEnabled() && type !== 'quiet') { // if nothing has been generated yet.. - if (tokens_already_generated === 0) { - // if the max gen setting is > 50...( - if (parseInt(amount_gen) >= power_user.multigen_first_chunk) { - // then only try to make 50 this cycle.. - this_amount_gen = power_user.multigen_first_chunk; - } - else { - // otherwise, make as much as the max amount request. - this_amount_gen = parseInt(amount_gen); - } - } - // if we already received some generated text... - else { - // if the remaining tokens to be made is less than next potential cycle count - if (parseInt(amount_gen) - tokens_already_generated < power_user.multigen_next_chunks) { - // subtract already generated amount from the desired max gen amount - this_amount_gen = parseInt(amount_gen) - tokens_already_generated; - } - else { - // otherwise make the standard cycle amount (first 50, and 30 after that) - this_amount_gen = power_user.multigen_next_chunks; - } - } + this_amount_gen = getMultigenAmount(); } + let thisPromptBits = []; + if (main_api == 'kobold' && horde_settings.use_horde && horde_settings.auto_adjust_response_length) { this_amount_gen = Math.min(this_amount_gen, adjustedParams.maxLength); this_amount_gen = Math.max(this_amount_gen, MIN_AMOUNT_GEN); // prevent validation errors @@ -2253,28 +2130,41 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, generate_data = getKoboldGenerationData(finalPromt, this_settings, this_amount_gen, maxContext, isImpersonate); } } - - if (main_api == 'textgenerationwebui') { + else if (main_api == 'textgenerationwebui') { generate_data = getTextGenGenerationData(finalPromt, this_amount_gen, isImpersonate); } - - if (main_api == 'novel') { + else if (main_api == 'novel') { const this_settings = novelai_settings[novelai_setting_names[nai_settings.preset_settings_novel]]; generate_data = getNovelGenerationData(finalPromt, this_settings); } + else if (main_api == 'openai') { + let [prompt, counts] = await prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldInfoAfter, afterScenarioAnchor, promptBias, type); + generate_data = { prompt: prompt }; + + // counts will return false if the user has not enabled the token breakdown feature + if (counts) { + parseTokenCounts(counts, thisPromptBits); + } + + setInContextMessages(openai_messages_count, type); + } else if (main_api == 'poe') { + generate_data = { prompt: finalPromt }; + } + + if (power_user.console_log_prompts) { + + console.log(generate_data.prompt); + } let generate_url = getGenerateUrl(); console.log('rungenerate calling API'); if (main_api == 'openai') { - let prompt = await prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldInfoAfter, afterScenarioAnchor, promptBias, type); - setInContextMessages(openai_messages_count, type); - if (isStreamingEnabled() && type !== 'quiet') { - streamingProcessor.generator = await sendOpenAIRequest(type, prompt, streamingProcessor.abortController.signal); + streamingProcessor.generator = await sendOpenAIRequest(type, generate_data.prompt, streamingProcessor.abortController.signal); } else { - sendOpenAIRequest(type, prompt).then(onSuccess).catch(onError); + sendOpenAIRequest(type, generate_data.prompt).then(onSuccess).catch(onError); } } else if (main_api == 'kobold' && horde_settings.use_horde) { @@ -2288,7 +2178,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, generatePoe(type, finalPromt).then(onSuccess).catch(onError); } } - else if (main_api == 'textgenerationwebui' && textgenerationwebui_settings.streaming && type !== 'quiet') { + else if (main_api == 'textgenerationwebui' && isStreamingEnabled() && type !== 'quiet') { streamingProcessor.generator = await generateTextGenWithStreaming(generate_data, streamingProcessor.abortController.signal); } else { @@ -2307,27 +2197,44 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, }); //end of "if not data error" } + //set array object for prompt token itemization of this message + let currentArrayEntry = Number(thisPromptBits.length - 1); + let additionalPromptStuff = { + ...thisPromptBits[currentArrayEntry], + rawPrompt: generate_data.prompt, + mesId: Number(count_view_mes), + worldInfoBefore: worldInfoBefore, + allAnchors: allAnchors, + summarizeString: (extension_prompts['1_memory']?.value || ''), + authorsNoteString: (extension_prompts['2_floating_prompt']?.value || ''), + worldInfoString: worldInfoString, + storyString: storyString, + worldInfoAfter: worldInfoAfter, + afterScenarioAnchor: afterScenarioAnchor, + examplesString: examplesString, + mesSendString: mesSendString, + generatedPromtCache: generatedPromtCache, + promptBias: promptBias, + finalPromt: finalPromt, + charDescription: charDescription, + charPersonality: charPersonality, + scenarioText: scenarioText, + this_max_context: this_max_context, + padding: power_user.token_padding, + main_api: main_api, + }; + + thisPromptBits = additionalPromptStuff; + + //console.log(thisPromptBits); + + itemizedPrompts.push(thisPromptBits); + //console.log(`pushed prompt bits to itemizedPrompts array. Length is now: ${itemizedPrompts.length}`); + if (isStreamingEnabled() && type !== 'quiet') { hideSwipeButtons(); let getMessage = await streamingProcessor.generate(); - // Cohee: Basically a dead-end code... (disabled by isStreamingEnabled) - // I wasn't able to get multigen working with real streaming - // consistently without screwing the interim prompting - if (isMultigenEnabled()) { - tokens_already_generated += this_amount_gen; - message_already_generated += getMessage; - promptBias = ''; - if (!streamingProcessor.isStopped && shouldContinueMultigen(getMessage, isImpersonate)) { - streamingProcessor.isFinished = false; - runGenerate(getMessage); - console.log('returning to make generate again'); - return; - } - - getMessage = message_already_generated; - } - if (streamingProcessor && !streamingProcessor.isStopped && streamingProcessor.isFinished) { streamingProcessor.onFinishStreaming(streamingProcessor.messageId, getMessage); streamingProcessor = null; @@ -2361,7 +2268,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, ({ type, getMessage } = saveReply('append', getMessage, this_mes_is_name, title)); } } else { - let chunk = cleanUpMessage(message_already_generated, true); + let chunk = cleanUpMessage(message_already_generated, true, true); let extract = extractNameFromMessage(chunk, force_name2, isImpersonate); $('#send_textarea').val(extract.getMessage).trigger('input'); } @@ -2375,7 +2282,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, return; } - getMessage = message_already_generated; + getMessage = message_already_generated.substring(magFirst.length); } //Formating @@ -2416,10 +2323,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, // regenerate with character speech reenforced // to make sure we leave on swipe type while also adding the name2 appendage setTimeout(() => { - let newType = type == "swipe" ? "swipe" : "force_name2"; - newType = isImpersonate ? type : newType; - - Generate(newType, { automatic_trigger: false, force_name2: true }); + Generate(type, { automatic_trigger, force_name2: true, resolve, reject, quiet_prompt, force_chid }); }, generate_loop_counter * 1000); } } else { @@ -2434,13 +2338,14 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, showSwipeButtons(); setGenerationProgress(0); $('.mes_buttons:last').show(); + + if (type !== 'quiet') { + resolve(); + } }; function onError(jqXHR, exception) { - if (type == 'quiet') { - reject(exception); - } - + reject(exception); $("#send_textarea").removeAttr('disabled'); is_send_press = false; activateSendButtons(); @@ -2461,9 +2366,156 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, //console.log('generate ending'); } //generate ends +function sendMessageAsUser(textareaText, messageBias) { + chat[chat.length] = {}; + chat[chat.length - 1]['name'] = name1; + chat[chat.length - 1]['is_user'] = true; + chat[chat.length - 1]['is_name'] = true; + chat[chat.length - 1]['send_date'] = humanizedDateTime(); + chat[chat.length - 1]['mes'] = textareaText; + chat[chat.length - 1]['extra'] = {}; + + if (messageBias) { + console.log('checking bias'); + chat[chat.length - 1]['extra']['bias'] = messageBias; + } + //console.log('Generate calls addOneMessage'); + addOneMessage(chat[chat.length - 1]); +} + +function getMaxContextSize() { + let this_max_context = 1487; + if (main_api == 'kobold' || main_api == 'textgenerationwebui') { + this_max_context = (max_context - amount_gen); + } + if (main_api == 'novel') { + if (novel_tier === 1) { + this_max_context = 1024; + } else { + this_max_context = 2048 - 60; //fix for fat tokens + if (nai_settings.model_novel == 'krake-v2') { + this_max_context -= 160; + } + } + } + if (main_api == 'openai') { + this_max_context = oai_settings.openai_max_context; + } + if (main_api == 'poe') { + this_max_context = Number(max_context); + } + return this_max_context; +} + +function parseTokenCounts(counts, thisPromptBits) { + const breakdown_bar = $('#token_breakdown div:first-child'); + breakdown_bar.empty(); + + const total = Object.values(counts).filter(x => !Number.isNaN(x)).reduce((acc, val) => acc + val, 0); + + thisPromptBits.push({ + oaiStartTokens: Object.entries(counts)[0][1], + oaiPromptTokens: Object.entries(counts)[1][1], + oaiBiasTokens: Object.entries(counts)[2][1], + oaiNudgeTokens: Object.entries(counts)[3][1], + oaiJailbreakTokens: Object.entries(counts)[4][1], + oaiImpersonateTokens: Object.entries(counts)[5][1], + oaiExamplesTokens: Object.entries(counts)[6][1], + oaiConversationTokens: Object.entries(counts)[7][1], + oaiTotalTokens: total, + }); + + Object.entries(counts).forEach(([type, value]) => { + if (value === 0) { + return; + } + const percent_value = (value / total) * 100; + const color = uniqolor(type, { saturation: 50, lightness: 75, }).color; + const bar = document.createElement('div'); + bar.style.width = `${percent_value}%`; + bar.classList.add('token_breakdown_segment'); + bar.style.backgroundColor = color + 'AA'; + bar.style.borderColor = color + 'FF'; + bar.innerText = value; + bar.title = `${type}: ${percent_value.toFixed(2)}%`; + breakdown_bar.append(bar); + }); +} + +function adjustChatsSeparator(mesSendString) { + if (power_user.custom_chat_separator && power_user.custom_chat_separator.length) { + mesSendString = power_user.custom_chat_separator + '\n' + mesSendString; + } + + // if chat start formatting is disabled + else if (power_user.disable_start_formatting) { + mesSendString = mesSendString; + } + + // add non-pygma dingus + else if (!is_pygmalion) { + mesSendString = '\nThen the roleplay chat between ' + name1 + ' and ' + name2 + ' begins.\n' + mesSendString; + } + + // add pygma + else { + mesSendString = '\n' + mesSendString; + //mesSendString = mesSendString; //This edit simply removes the first "" that is prepended to all context prompts + } + + return mesSendString; +} + +function appendZeroDepthAnchor(force_name2, zeroDepthAnchor, finalPromt) { + const trimBothEnds = !force_name2 && !is_pygmalion; + let trimmedPrompt = (trimBothEnds ? zeroDepthAnchor.trim() : zeroDepthAnchor.trimEnd()); + + if (trimBothEnds && !finalPromt.endsWith('\n')) { + finalPromt += '\n'; + } + + finalPromt += trimmedPrompt; + + if (force_name2 || is_pygmalion) { + finalPromt += ' '; + } + + return finalPromt; +} + +function getMultigenAmount() { + let this_amount_gen = parseInt(amount_gen); + + if (tokens_already_generated === 0) { + // if the max gen setting is > 50...( + if (parseInt(amount_gen) >= power_user.multigen_first_chunk) { + // then only try to make 50 this cycle.. + this_amount_gen = power_user.multigen_first_chunk; + } + else { + // otherwise, make as much as the max amount request. + this_amount_gen = parseInt(amount_gen); + } + } + // if we already received some generated text... + else { + // if the remaining tokens to be made is less than next potential cycle count + if (parseInt(amount_gen) - tokens_already_generated < power_user.multigen_next_chunks) { + // subtract already generated amount from the desired max gen amount + this_amount_gen = parseInt(amount_gen) - tokens_already_generated; + } + else { + // otherwise make the standard cycle amount (first 50, and 30 after that) + this_amount_gen = power_user.multigen_next_chunks; + } + } + return this_amount_gen; +} + function promptItemize(itemizedPrompts, requestedMesId) { - let incomingMesId = Number(requestedMesId); - let thisPromptSet = undefined; + var incomingMesId = Number(requestedMesId); + console.log(`looking for MesId ${incomingMesId}`); + var thisPromptSet = undefined; for (var i = 0; i < itemizedPrompts.length; i++) { if (itemizedPrompts[i].mesId === incomingMesId) { @@ -2477,48 +2529,218 @@ function promptItemize(itemizedPrompts, requestedMesId) { return null; } - let finalPromptTokens = getTokenCount(itemizedPrompts[thisPromptSet].finalPromt); - let allAnchorsTokens = getTokenCount(itemizedPrompts[thisPromptSet].allAnchors); - let summarizeStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].summarizeString); - let authorsNoteStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].authorsNoteString); - let afterScenarioAnchorTokens = getTokenCount(itemizedPrompts[thisPromptSet].afterScenarioAnchor); - let zeroDepthAnchorTokens = getTokenCount(itemizedPrompts[thisPromptSet].afterScenarioAnchor); - let worldInfoStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].worldInfoString); - let storyStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].storyString); - let examplesStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].examplesString); - let charPersonalityTokens = getTokenCount(itemizedPrompts[thisPromptSet].charPersonality); - let charDescriptionTokens = getTokenCount(itemizedPrompts[thisPromptSet].charDescription); - let scenarioTextTokens = getTokenCount(itemizedPrompts[thisPromptSet].scenarioText); - let promptBiasTokens = getTokenCount(itemizedPrompts[thisPromptSet].promptBias); - let mesSendStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].mesSendString) - let ActualChatHistoryTokens = mesSendStringTokens - allAnchorsTokens + power_user.token_padding; - let thisPrompt_max_context = itemizedPrompts[thisPromptSet].this_max_context; - let thisPrompt_padding = itemizedPrompts[thisPromptSet].padding; + //these happen regardless of API + var charPersonalityTokens = getTokenCount(itemizedPrompts[thisPromptSet].charPersonality); + var charDescriptionTokens = getTokenCount(itemizedPrompts[thisPromptSet].charDescription); + var scenarioTextTokens = getTokenCount(itemizedPrompts[thisPromptSet].scenarioText); + var allAnchorsTokens = getTokenCount(itemizedPrompts[thisPromptSet].allAnchors); + var summarizeStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].summarizeString); + var authorsNoteStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].authorsNoteString); + var afterScenarioAnchorTokens = getTokenCount(itemizedPrompts[thisPromptSet].afterScenarioAnchor); + var zeroDepthAnchorTokens = getTokenCount(itemizedPrompts[thisPromptSet].afterScenarioAnchor); + var worldInfoStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].worldInfoString); + var thisPrompt_max_context = itemizedPrompts[thisPromptSet].this_max_context; + var thisPrompt_padding = itemizedPrompts[thisPromptSet].padding; + var promptBiasTokens = getTokenCount(itemizedPrompts[thisPromptSet].promptBias); + var this_main_api = itemizedPrompts[thisPromptSet].main_api; - let totalTokensInPrompt = - storyStringTokens + //chardefs total - worldInfoStringTokens + - ActualChatHistoryTokens + //chat history - allAnchorsTokens + // AN and/or legacy anchors - //afterScenarioAnchorTokens + //only counts if AN is set to 'after scenario' - //zeroDepthAnchorTokens + //same as above, even if AN not on 0 depth - promptBiasTokens + //{{}} - - thisPrompt_padding; //not sure this way of calculating is correct, but the math results in same value as 'finalPromt' + if (this_main_api == 'openai') { + //for OAI API + //console.log('-- Counting OAI Tokens'); - let storyStringTokensPercentage = ((storyStringTokens / (totalTokensInPrompt + thisPrompt_padding)) * 100).toFixed(2); - let ActualChatHistoryTokensPercentage = ((ActualChatHistoryTokens / (totalTokensInPrompt + thisPrompt_padding)) * 100).toFixed(2); - let promptBiasTokensPercentage = ((promptBiasTokens / (totalTokensInPrompt + thisPrompt_padding)) * 100).toFixed(2); - let worldInfoStringTokensPercentage = ((worldInfoStringTokens / (totalTokensInPrompt + thisPrompt_padding)) * 100).toFixed(2); - let allAnchorsTokensPercentage = ((allAnchorsTokens / (totalTokensInPrompt + thisPrompt_padding)) * 100).toFixed(2); - let selectedTokenizer = $("#tokenizer").find(':selected').text(); - callPopup( - ` + //var finalPromptTokens = itemizedPrompts[thisPromptSet].oaiTotalTokens; + var oaiStartTokens = itemizedPrompts[thisPromptSet].oaiStartTokens; + var oaiPromptTokens = itemizedPrompts[thisPromptSet].oaiPromptTokens; + var ActualChatHistoryTokens = itemizedPrompts[thisPromptSet].oaiConversationTokens; + var examplesStringTokens = itemizedPrompts[thisPromptSet].oaiExamplesTokens; + var oaiBiasTokens = itemizedPrompts[thisPromptSet].oaiBiasTokens; + var oaiJailbreakTokens = itemizedPrompts[thisPromptSet].oaiJailbreakTokens; + var oaiNudgeTokens = itemizedPrompts[thisPromptSet].oaiNudgeTokens; + var oaiImpersonateTokens = itemizedPrompts[thisPromptSet].oaiImpersonateTokens; + var finalPromptTokens = + oaiBiasTokens + + oaiImpersonateTokens + + oaiJailbreakTokens + + oaiNudgeTokens + + oaiPromptTokens + + ActualChatHistoryTokens + + charDescriptionTokens + + charPersonalityTokens + + allAnchorsTokens + + worldInfoStringTokens + + examplesStringTokens; + // OAI doesn't use padding + thisPrompt_padding = 0; + // Max context size - max completion tokens + thisPrompt_max_context = (oai_settings.openai_max_context - oai_settings.openai_max_tokens); + } else { + //for non-OAI APIs + //console.log('-- Counting non-OAI Tokens'); + var finalPromptTokens = getTokenCount(itemizedPrompts[thisPromptSet].finalPromt); + var storyStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].storyString); + var examplesStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].examplesString); + var mesSendStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].mesSendString) + var ActualChatHistoryTokens = mesSendStringTokens - allAnchorsTokens + power_user.token_padding; + + var totalTokensInPrompt = + storyStringTokens + //chardefs total + worldInfoStringTokens + + ActualChatHistoryTokens + //chat history + allAnchorsTokens + // AN and/or legacy anchors + //afterScenarioAnchorTokens + //only counts if AN is set to 'after scenario' + //zeroDepthAnchorTokens + //same as above, even if AN not on 0 depth + promptBiasTokens; //{{}} + //- thisPrompt_padding; //not sure this way of calculating is correct, but the math results in same value as 'finalPromt' + } + + if (this_main_api == 'openai') { + //console.log('-- applying % on OAI tokens'); + var oaiStartTokensPercentage = ((oaiStartTokens / (finalPromptTokens)) * 100).toFixed(2); + var storyStringTokensPercentage = ((oaiPromptTokens / (finalPromptTokens)) * 100).toFixed(2); + var ActualChatHistoryTokensPercentage = ((ActualChatHistoryTokens / (finalPromptTokens)) * 100).toFixed(2); + var promptBiasTokensPercentage = ((oaiBiasTokens / (finalPromptTokens)) * 100).toFixed(2); + var worldInfoStringTokensPercentage = ((worldInfoStringTokens / (finalPromptTokens)) * 100).toFixed(2); + var allAnchorsTokensPercentage = ((allAnchorsTokens / (finalPromptTokens)) * 100).toFixed(2); + var selectedTokenizer = `tiktoken (${oai_settings.openai_model})`; + var oaiSystemTokens = oaiImpersonateTokens + oaiJailbreakTokens + oaiNudgeTokens + oaiStartTokens; + var oaiSystemTokensPercentage = ((oaiSystemTokens / (finalPromptTokens)) * 100).toFixed(2); + + } else { + //console.log('-- applying % on non-OAI tokens'); + var storyStringTokensPercentage = ((storyStringTokens / (totalTokensInPrompt)) * 100).toFixed(2); + var ActualChatHistoryTokensPercentage = ((ActualChatHistoryTokens / (totalTokensInPrompt)) * 100).toFixed(2); + var promptBiasTokensPercentage = ((promptBiasTokens / (totalTokensInPrompt)) * 100).toFixed(2); + var worldInfoStringTokensPercentage = ((worldInfoStringTokens / (totalTokensInPrompt)) * 100).toFixed(2); + var allAnchorsTokensPercentage = ((allAnchorsTokens / (totalTokensInPrompt)) * 100).toFixed(2); + var selectedTokenizer = $("#tokenizer").find(':selected').text(); + } + + if (this_main_api == 'openai') { + //console.log('-- calling popup for OAI tokens'); + callPopup( + `

Prompt Itemization

- Tokenizer: ${selectedTokenizer}
+ Tokenizer: TikToken
+ API Used: ${this_main_api}
Only the white numbers really matter. All numbers are estimates. Grey color items may not have been included in the context due to certain prompt format settings. + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
System Info:
+
${oaiSystemTokens}
+
+
+
-- Chat Start:
+
${oaiStartTokens}
+
+
+
-- Jailbreak:
+
${oaiJailbreakTokens}
+
+
+
-- NSFW:
+
??
+
+
+
-- Nudge:
+
${oaiNudgeTokens}
+
+
+
-- Impersonate:
+
${oaiImpersonateTokens}
+
+
+
+
+
Prompt Tokens:
+
${oaiPromptTokens}
+
+
+
-- Description:
+
${charDescriptionTokens}
+
+
+
-- Personality:
+
${charPersonalityTokens}
+
+
+
-- Scenario:
+
${scenarioTextTokens}
+
+
+
-- Examples:
+
${examplesStringTokens}
+
+
+
+
World Info:
+
${worldInfoStringTokens}
+
+
+
Chat History:
+
${ActualChatHistoryTokens}
+
+
+
+
Extensions:
+
${allAnchorsTokens}
+
+
+
-- Summarize:
+
${summarizeStringTokens}
+
+
+
-- Author's Note:
+
${authorsNoteStringTokens}
+
+
+
+
{{}} Bias:
${oaiBiasTokens}
+
+
+ +
+
+
+
+
Total Tokens in Prompt:
${finalPromptTokens}
+
+
+
Max Context (Context Size - Response Length):
${thisPrompt_max_context}
+
+
+
+
+ `, 'text' + ); + + } else { + //console.log('-- calling popup for non-OAI tokens'); + callPopup( + ` +

Prompt Itemization

+ Tokenizer: ${selectedTokenizer}
+ API Used: ${this_main_api}
+ + Only the white numbers really matter. All numbers are estimates. + Grey color items may not have been included in the context due to certain prompt format settings. + +
@@ -2599,7 +2821,8 @@ function promptItemize(itemizedPrompts, requestedMesId) {

`, 'text' - ); + ); + } } function setInContextMessages(lastmsg, type) { @@ -2769,7 +2992,11 @@ function extractMessageFromData(data) { return getMessage; } -function cleanUpMessage(getMessage, isImpersonate) { +function cleanUpMessage(getMessage, isImpersonate, displayIncompleteSentences = false) { + if (!displayIncompleteSentences && power_user.trim_sentences) { + getMessage = end_trim_to_sentence(getMessage, power_user.include_newline); + } + if (power_user.collapse_newlines) { getMessage = collapseNewlines(getMessage); } @@ -2913,6 +3140,10 @@ function saveReply(type, getMessage, this_mes_is_name, title) { const item = chat[chat.length - 1]; if (item['swipe_id'] !== undefined) { item['swipes'][item['swipes'].length - 1] = item['mes']; + } else { + item['swipe_id'] = 0; + item['swipes'] = []; + item['swipes'][0] = chat[chat.length - 1]['mes']; } return { type, getMessage }; @@ -3325,8 +3556,10 @@ function changeMainAPI() { // Hide common settings for OpenAI if (selectedVal == "openai") { $("#common-gen-settings-block").css("display", "none"); + //$("#token_breakdown").css("display", "flex"); } else { $("#common-gen-settings-block").css("display", "block"); + //$("#token_breakdown").css("display", "none"); } // Hide amount gen for poe if (selectedVal == "poe") { @@ -3490,30 +3723,15 @@ async function getSettings(type) { `#settings_perset_novel option[value=${novelai_setting_names[nai_settings.preset_settings_novel]}]` ).attr("selected", "true"); - //Load AI model config settings (temp, context length, anchors, and anchor order) + //Load AI model config settings amount_gen = settings.amount_gen; if (settings.max_context !== undefined) max_context = parseInt(settings.max_context); - if (settings.anchor_order !== undefined) - anchor_order = parseInt(settings.anchor_order); - if (settings.style_anchor !== undefined) - style_anchor = !!settings.style_anchor; - if (settings.character_anchor !== undefined) - character_anchor = !!settings.character_anchor; - - $("#style_anchor").prop("checked", style_anchor); - $("#character_anchor").prop("checked", character_anchor); - $("#anchor_order option[value=" + anchor_order + "]").attr( - "selected", - "true" - ); swipes = settings.swipes !== undefined ? !!settings.swipes : true; // enable swipes by default $('#swipes-checkbox').prop('checked', swipes); /// swipecode - //console.log('getSettings -- swipes = ' + swipes + '. toggling box'); hideSwipeButtons(); - //console.log('getsettings calling showswipebtns'); showSwipeButtons(); // Kobold @@ -3611,9 +3829,6 @@ async function saveSettings(type) { user_avatar: user_avatar, amount_gen: amount_gen, max_context: max_context, - anchor_order: anchor_order, - style_anchor: style_anchor, - character_anchor: character_anchor, main_api: main_api, world_info: world_info, world_info_depth: world_info_depth, @@ -5552,17 +5767,6 @@ $(document).ready(function () { ////////////////////////////////////////////////////////////// - - $("#style_anchor").change(function () { - style_anchor = !!$("#style_anchor").prop("checked"); - saveSettingsDebounced(); - }); - - $("#character_anchor").change(function () { - character_anchor = !!$("#character_anchor").prop("checked"); - saveSettingsDebounced(); - }); - $("#select_chat_cross").click(function () { $("#shadow_select_chat_popup").transition({ opacity: 0, @@ -5613,6 +5817,18 @@ $(document).ready(function () { } }) + $(document).on("pointerup", "#showRawPrompt", function () { + //let mesIdForItemization = $(this).closest('.mes').attr('mesId'); + //console.log(generate_data.prompt); + console.log(itemizedPrompts[0].rawPrompt); + $("#rawPromptWrapper").html(itemizedPrompts[0].rawPrompt.replace(/\n/g, '
')); + rawPromptPopper.update(); + $('#rawPromptPopup').toggle(); + + //Popper(itemizedPrompts, mesIdForItemization); + + }) + //******************** //***Message Editor*** @@ -5842,11 +6058,6 @@ $(document).ready(function () { is_api_button_press_novel = true; }); - $("#anchor_order").change(function () { - anchor_order = parseInt($("#anchor_order").find(":selected").val()); - saveSettingsDebounced(); - }); - //**************************CHARACTER IMPORT EXPORT*************************// $("#character_import_button").click(function () { $("#character_import_file").click(); @@ -6081,6 +6292,7 @@ $(document).ready(function () { '#shadow_popup', '#world_popup', '.ui-widget', + '.text_pole', ]; for (const id of forbiddenTargets) { if (clickTarget.closest(id).length > 0) { @@ -6102,7 +6314,10 @@ $(document).ready(function () { } }); - $(document).on('click', '.inline-drawer-toggle', function () { + $(document).on('click', '.inline-drawer-toggle', function (e) { + if ($(e.target).hasClass('text_pole')) { + return; + }; var icon = $(this).find('.inline-drawer-icon'); icon.toggleClass('down up'); icon.toggleClass('fa-circle-chevron-down fa-circle-chevron-up'); diff --git a/public/scripts/RossAscends-mods.js b/public/scripts/RossAscends-mods.js index b17729753..952adedd7 100644 --- a/public/scripts/RossAscends-mods.js +++ b/public/scripts/RossAscends-mods.js @@ -30,11 +30,16 @@ import { import { sortByCssOrder } from "./utils.js"; var NavToggle = document.getElementById("nav-toggle"); + var RPanelPin = document.getElementById("rm_button_panel_pin"); var LPanelPin = document.getElementById("lm_button_panel_pin"); -var SelectedCharacterTab = document.getElementById("rm_button_selected_ch"); +var WIPanelPin = document.getElementById("WI_panel_pin"); + var RightNavPanel = document.getElementById("right-nav-panel"); -var LeftNavPanel = document.getElementById("left-nav-panel") +var LeftNavPanel = document.getElementById("left-nav-panel"); +var WorldInfo = document.getElementById("WorldInfo"); + +var SelectedCharacterTab = document.getElementById("rm_button_selected_ch"); var AdvancedCharDefsPopup = document.getElementById("character_popup"); var ConfirmationPopup = document.getElementById("dialogue_popup"); var AutoConnectCheckbox = document.getElementById("auto-connect-checkbox"); @@ -412,23 +417,18 @@ function OpenNavPanels() { if (LoadLocalBool("NavLockOn") == true && LoadLocalBool("NavOpened") == true) { //console.log("RA -- clicking right nav to open"); $("#rightNavDrawerIcon").click(); - } else { - /* console.log('didnt see reason to open right nav on load: R-nav locked? ' + - LoadLocalBool("NavLockOn") - + ' R-nav was open before? ' + - LoadLocalBool("NavOpened" == true)); */ } //auto-open L nav if locked and previously open - if (LoadLocalBool("LNavLockOn") == true && LoadLocalBool("LNavOpened") == true) { console.log("RA -- clicking left nav to open"); $("#leftNavDrawerIcon").click(); - } else { - /* console.log('didnt see reason to open left nav on load: L-Nav Locked? ' + - LoadLocalBool("LNavLockOn") - + ' L-nav was open before? ' + - LoadLocalBool("LNavOpened" == true)); */ + } + + //auto-open WI if locked and previously open + if (LoadLocalBool("WINavLockOn") == true && LoadLocalBool("WINavOpened") == true) { + console.log("RA -- clicking WI to open"); + $("#WIDrawerIcon").click(); } } @@ -438,6 +438,7 @@ dragElement(document.getElementById("sheld")); dragElement(document.getElementById("left-nav-panel")); dragElement(document.getElementById("right-nav-panel")); dragElement(document.getElementById("avatar_zoom_popup")); +dragElement(document.getElementById("WorldInfo")); @@ -546,6 +547,7 @@ function dragElement(elmnt) { elmnt.style.top = (elmnt.offsetTop - pos2) + "px"; $(elmnt).css("bottom", "unset"); $(elmnt).css("right", "unset"); + $(elmnt).css("margin", "unset"); /* console.log(` offsetLeft: ${elmnt.offsetLeft}, offsetTop: ${elmnt.offsetTop} @@ -614,7 +616,7 @@ $("document").ready(function () { if ($(RightNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) { $(RightNavPanel).slideToggle(200, "swing"); - $(rightNavDrawerIcon).toggleClass('openIcon closedIcon'); + //$(rightNavDrawerIcon).toggleClass('openIcon closedIcon'); $(RightNavPanel).toggleClass('openDrawer closedDrawer'); } } @@ -630,12 +632,30 @@ $("document").ready(function () { if ($(LeftNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) { $(LeftNavPanel).slideToggle(200, "swing"); - $(leftNavDrawerIcon).toggleClass('openIcon closedIcon'); + //$(leftNavDrawerIcon).toggleClass('openIcon closedIcon'); $(LeftNavPanel).toggleClass('openDrawer closedDrawer'); } } }); + $(WIPanelPin).on("click", function () { + SaveLocal("WINavLockOn", $(WIPanelPin).prop("checked")); + if ($(WIPanelPin).prop("checked") == true) { + console.log('adding pin class to WI'); + $(WorldInfo).addClass('pinnedOpen'); + } else { + console.log('removing pin class from WI'); + $(WorldInfo).removeClass('pinnedOpen'); + + if ($(WorldInfo).hasClass('openDrawer') && $('.openDrawer').length > 1) { + console.log('closing WI after lock removal'); + $(WorldInfo).slideToggle(200, "swing"); + //$(WorldInfoDrawerIcon).toggleClass('openIcon closedIcon'); + $(WorldInfo).toggleClass('openDrawer closedDrawer'); + } + } + }); + // read the state of right Nav Lock and apply to rightnav classlist $(RPanelPin).prop('checked', LoadLocalBool("NavLockOn")); if (LoadLocalBool("NavLockOn") == true) { @@ -657,6 +677,18 @@ $("document").ready(function () { $(LeftNavPanel).addClass('pinnedOpen'); } + // read the state of left Nav Lock and apply to leftnav classlist + $(WIPanelPin).prop('checked', LoadLocalBool("WINavLockOn")); + if (LoadLocalBool("WINavLockOn") == true) { + //console.log('setting pin class via local var'); + $(WorldInfo).addClass('pinnedOpen'); + } + + if ($(WIPanelPin).prop('checked' == true)) { + console.log('setting pin class via checkbox state'); + $(WorldInfo).addClass('pinnedOpen'); + } + //save state of Right nav being open or closed $("#rightNavDrawerIcon").on("click", function () { if (!$("#rightNavDrawerIcon").hasClass('openIcon')) { @@ -671,6 +703,13 @@ $("document").ready(function () { } else { SaveLocal('LNavOpened', 'false'); } }); + //save state of Left nav being open or closed + $("#WorldInfo").on("click", function () { + if (!$("#WorldInfo").hasClass('openIcon')) { + SaveLocal('WINavOpened', 'true'); + } else { SaveLocal('WINavOpened', 'false'); } + }); + var chatbarInFocus = false; $('#send_textarea').focus(function () { chatbarInFocus = true; diff --git a/public/scripts/extensions/stable-diffusion/manifest.json b/public/scripts/extensions/stable-diffusion/manifest.json index 13f8db021..37b437638 100644 --- a/public/scripts/extensions/stable-diffusion/manifest.json +++ b/public/scripts/extensions/stable-diffusion/manifest.json @@ -1,10 +1,10 @@ { "display_name": "Stable Diffusion", "loading_order": 10, - "requires": [ + "requires": [], + "optional": [ "sd" ], - "optional": [], "js": "index.js", "css": "style.css", "author": "Cohee#1207", diff --git a/public/scripts/extensions/tts/index.js b/public/scripts/extensions/tts/index.js index 4eeded46c..31c23ce8b 100644 --- a/public/scripts/extensions/tts/index.js +++ b/public/scripts/extensions/tts/index.js @@ -1,4 +1,4 @@ -import { callPopup, isMultigenEnabled, is_send_press, saveSettingsDebounced } from '../../../script.js' +import { callPopup, cancelTtsPlay, isMultigenEnabled, is_send_press, saveSettingsDebounced } from '../../../script.js' import { extension_settings, getContext } from '../../extensions.js' import { getStringHash } from '../../utils.js' import { ElevenLabsTtsProvider } from './elevenlabs.js' @@ -24,9 +24,47 @@ let ttsProviders = { let ttsProvider let ttsProviderName +async function onNarrateOneMessage() { + cancelTtsPlay(); + const context = getContext(); + const id = $(this).closest('.mes').attr('mesid'); + const message = context.chat[id]; + + if (!message) { + return; + } + + currentTtsJob = null; + audioElement.pause(); + audioElement.currentTime = 0; + ttsJobQueue.splice(0, ttsJobQueue.length); + audioJobQueue.splice(0, audioJobQueue.length); + ttsJobQueue.push(message); + moduleWorker(); +} + +let isWorkerBusy = false; + +async function moduleWorkerWrapper() { + // Don't touch me I'm busy... + if (isWorkerBusy) { + return; + } + + // I'm free. Let's update! + try { + isWorkerBusy = true; + await moduleWorker(); + } + finally { + isWorkerBusy = false; + } +} + async function moduleWorker() { // Primarily determinign when to add new chat to the TTS queue const enabled = $('#tts_enabled').is(':checked') + $('body').toggleClass('tts', enabled); if (!enabled) { return } @@ -296,6 +334,7 @@ function loadSettings() { ) $('#tts_narrate_dialogues').prop('checked', extension_settings.tts.narrate_dialogues_only) $('#tts_narrate_quoted').prop('checked', extension_settings.tts.narrate_quoted_only) + $('body').toggleClass('tts', extension_settings.tts.enabled); } const defaultSettings = { @@ -507,10 +546,11 @@ $(document).ready(function () { $('#tts_provider').append($("