Move itemized prompts into separate module (#4229) * Move itemized prompts into separate module * Update public/scripts/itemized-prompts.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update public/scripts/itemized-prompts.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed| @@ -4,9 +4,7 @@ import { | ||
| 4 | 4 | Fuse, |
| 5 | 5 | DOMPurify, |
| 6 | 6 | hljs, |
| 7 | - localforage, | |
| 8 | 7 | Handlebars, |
| 9 | - DiffMatchPatch, | |
| 10 | 8 | SVGInject, |
| 11 | 9 | Popper, |
| 12 | 10 | initLibraryShims, |
| @@ -297,6 +295,7 @@ import { extractReasoningFromData, initReasoning, parseReasoningInSwipes, Prompt | ||
| 297 | 295 | import { accountStorage } from './scripts/util/AccountStorage.js'; |
| 298 | 296 | import { initWelcomeScreen, openPermanentAssistantChat, openPermanentAssistantCard, getPermanentAssistantAvatar } from './scripts/welcome-screen.js'; |
| 299 | 297 | import { initDataMaid } from './scripts/data-maid.js'; |
| 298 | +import { clearItemizedPrompts, deleteItemizedPrompts, findItemizedPromptSet, initItemizedPrompts, itemizedParams, itemizedPrompts, loadItemizedPrompts, promptItemize, replaceItemizedPromptText, saveItemizedPrompts } from './scripts/itemized-prompts.js'; | |
| 300 | 299 | |
| 301 | 300 | // API OBJECT FOR EXTERNAL WIRING |
| 302 | 301 | globalThis.SillyTavern = { |
| @@ -304,7 +303,9 @@ globalThis.SillyTavern = { | ||
| 304 | 303 | getContext, |
| 305 | 304 | }; |
| 306 | 305 | |
| 307 | -//exporting functions and vars for mods | |
| 306 | +/** | |
| 307 | + * Exports that were once part of this module. For backwards compatibility. | |
| 308 | + */ | |
| 308 | 309 | export { |
| 309 | 310 | user_avatar, |
| 310 | 311 | setUserAvatar, |
| @@ -314,6 +315,15 @@ export { | ||
| 314 | 315 | isOdd, |
| 315 | 316 | countOccurrences, |
| 316 | 317 | renderTemplate, |
| 318 | + promptItemize, | |
| 319 | + itemizedPrompts, | |
| 320 | + saveItemizedPrompts, | |
| 321 | + loadItemizedPrompts, | |
| 322 | + itemizedParams, | |
| 323 | + clearItemizedPrompts, | |
| 324 | + replaceItemizedPromptText, | |
| 325 | + deleteItemizedPrompts, | |
| 326 | + findItemizedPromptSet, | |
| 317 | 327 | }; |
| 318 | 328 | |
| 319 | 329 | /** |
| @@ -577,9 +587,6 @@ export let mesForShowdownParse; //intended to be used as a context to compare sh | ||
| 577 | 587 | export let converter; |
| 578 | 588 | |
| 579 | 589 | // array for prompt token calculations |
| 580 | -console.debug('initializing Prompt Itemization Array on Startup'); | |
| 581 | -const promptStorage = localforage.createInstance({ name: 'SillyTavern_Prompts' }); | |
| 582 | -export let itemizedPrompts = []; | |
| 583 | 590 | |
| 584 | 591 | export const systemUserName = 'SillyTavern System'; |
| 585 | 592 | export const neutralCharacterName = 'Assistant'; |
| @@ -928,8 +935,6 @@ var kobold_horde_model = ''; | ||
| 928 | 935 | |
| 929 | 936 | export let token; |
| 930 | 937 | |
| 931 | -var PromptArrayItemForRawPromptDisplay; | |
| 932 | -var priorPromptArrayItemForRawPromptDisplay; | |
| 933 | 938 | |
| 934 | 939 | /** The tag of the active character. (NOT the id) */ |
| 935 | 940 | export let active_character = ''; |
| @@ -1038,6 +1043,7 @@ async function firstLoadInit() { | ||
| 1038 | 1043 | await initScrapers(); |
| 1039 | 1044 | initCustomSelectedSamplers(); |
| 1040 | 1045 | initDataMaid(); |
| 1046 | + initItemizedPrompts(); | |
| 1041 | 1047 | addDebugFunctions(); |
| 1042 | 1048 | doDailyExtensionUpdatesCheck(); |
| 1043 | 1049 | await hideLoader(); |
| @@ -1102,92 +1108,6 @@ export function setActiveGroup(entityOrKey) { | ||
| 1102 | 1108 | if (active_group) active_character = null; |
| 1103 | 1109 | } |
| 1104 | 1110 | |
| 1105 | -/** | |
| 1106 | - * Gets the itemized prompts for a chat. | |
| 1107 | - * @param {string} chatId Chat ID to load | |
| 1108 | - */ | |
| 1109 | -export async function loadItemizedPrompts(chatId) { | |
| 1110 | - try { | |
| 1111 | - if (!chatId) { | |
| 1112 | - itemizedPrompts = []; | |
| 1113 | - return; | |
| 1114 | - } | |
| 1115 | - | |
| 1116 | - itemizedPrompts = await promptStorage.getItem(chatId); | |
| 1117 | - | |
| 1118 | - if (!itemizedPrompts) { | |
| 1119 | - itemizedPrompts = []; | |
| 1120 | - } | |
| 1121 | - } catch { | |
| 1122 | - console.log('Error loading itemized prompts for chat', chatId); | |
| 1123 | - itemizedPrompts = []; | |
| 1124 | - } | |
| 1125 | -} | |
| 1126 | - | |
| 1127 | -/** | |
| 1128 | - * Saves the itemized prompts for a chat. | |
| 1129 | - * @param {string} chatId Chat ID to save itemized prompts for | |
| 1130 | - */ | |
| 1131 | -export async function saveItemizedPrompts(chatId) { | |
| 1132 | - try { | |
| 1133 | - if (!chatId) { | |
| 1134 | - return; | |
| 1135 | - } | |
| 1136 | - | |
| 1137 | - await promptStorage.setItem(chatId, itemizedPrompts); | |
| 1138 | - } catch { | |
| 1139 | - console.log('Error saving itemized prompts for chat', chatId); | |
| 1140 | - } | |
| 1141 | -} | |
| 1142 | - | |
| 1143 | -/** | |
| 1144 | - * Replaces the itemized prompt text for a message. | |
| 1145 | - * @param {number} mesId Message ID to get itemized prompt for | |
| 1146 | - * @param {string} promptText New raw prompt text | |
| 1147 | - * @returns | |
| 1148 | - */ | |
| 1149 | -export async function replaceItemizedPromptText(mesId, promptText) { | |
| 1150 | - if (!Array.isArray(itemizedPrompts)) { | |
| 1151 | - itemizedPrompts = []; | |
| 1152 | - } | |
| 1153 | - | |
| 1154 | - const itemizedPrompt = itemizedPrompts.find(x => x.mesId === mesId); | |
| 1155 | - | |
| 1156 | - if (!itemizedPrompt) { | |
| 1157 | - return; | |
| 1158 | - } | |
| 1159 | - | |
| 1160 | - itemizedPrompt.rawPrompt = promptText; | |
| 1161 | -} | |
| 1162 | - | |
| 1163 | -/** | |
| 1164 | - * Deletes the itemized prompts for a chat. | |
| 1165 | - * @param {string} chatId Chat ID to delete itemized prompts for | |
| 1166 | - */ | |
| 1167 | -export async function deleteItemizedPrompts(chatId) { | |
| 1168 | - try { | |
| 1169 | - if (!chatId) { | |
| 1170 | - return; | |
| 1171 | - } | |
| 1172 | - | |
| 1173 | - await promptStorage.removeItem(chatId); | |
| 1174 | - } catch { | |
| 1175 | - console.log('Error deleting itemized prompts for chat', chatId); | |
| 1176 | - } | |
| 1177 | -} | |
| 1178 | - | |
| 1179 | -/** | |
| 1180 | - * Empties the itemized prompts array and caches. | |
| 1181 | - */ | |
| 1182 | -export async function clearItemizedPrompts() { | |
| 1183 | - try { | |
| 1184 | - await promptStorage.clear(); | |
| 1185 | - itemizedPrompts = []; | |
| 1186 | - } catch { | |
| 1187 | - console.log('Error clearing itemized prompts'); | |
| 1188 | - } | |
| 1189 | -} | |
| 1190 | - | |
| 1191 | 1111 | async function getStatusHorde() { |
| 1192 | 1112 | try { |
| 1193 | 1113 | const hordeStatus = await checkHordeStatus(); |
| @@ -2089,7 +2009,7 @@ export async function clearChat() { | ||
| 2089 | 2009 | } else { console.debug('saw no avatars'); } |
| 2090 | 2010 | |
| 2091 | 2011 | await saveItemizedPrompts(getCurrentChatId()); |
| 2092 | 2012 | itemizedPrompts.length = []0; |
| 2093 | 2013 | } |
| 2094 | 2014 | |
| 2095 | 2015 | export async function deleteLastMessage() { |
| @@ -5724,231 +5644,6 @@ async function duplicateCharacter() { | ||
| 5724 | 5644 | return ''; |
| 5725 | 5645 | } |
| 5726 | 5646 | |
| 5727 | -export async function itemizedParams(itemizedPrompts, thisPromptSet, incomingMesId) { | |
| 5728 | - const params = { | |
| 5729 | - charDescriptionTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].charDescription), | |
| 5730 | - charPersonalityTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].charPersonality), | |
| 5731 | - scenarioTextTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].scenarioText), | |
| 5732 | - userPersonaStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].userPersona), | |
| 5733 | - worldInfoStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].worldInfoString), | |
| 5734 | - allAnchorsTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].allAnchors), | |
| 5735 | - summarizeStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].summarizeString), | |
| 5736 | - authorsNoteStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].authorsNoteString), | |
| 5737 | - smartContextStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].smartContextString), | |
| 5738 | - beforeScenarioAnchorTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].beforeScenarioAnchor), | |
| 5739 | - afterScenarioAnchorTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].afterScenarioAnchor), | |
| 5740 | - zeroDepthAnchorTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].zeroDepthAnchor), // TODO: unused | |
| 5741 | - thisPrompt_padding: itemizedPrompts[thisPromptSet].padding, | |
| 5742 | - this_main_api: itemizedPrompts[thisPromptSet].main_api, | |
| 5743 | - chatInjects: await getTokenCountAsync(itemizedPrompts[thisPromptSet].chatInjects), | |
| 5744 | - chatVectorsStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].chatVectorsString), | |
| 5745 | - dataBankVectorsStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].dataBankVectorsString), | |
| 5746 | - modelUsed: chat[incomingMesId]?.extra?.model, | |
| 5747 | - apiUsed: chat[incomingMesId]?.extra?.api, | |
| 5748 | - presetName: itemizedPrompts[thisPromptSet].presetName || t`(Unknown)`, | |
| 5749 | - messagesCount: String(itemizedPrompts[thisPromptSet].messagesCount ?? ''), | |
| 5750 | - examplesCount: String(itemizedPrompts[thisPromptSet].examplesCount ?? ''), | |
| 5751 | - }; | |
| 5752 | - | |
| 5753 | - const getFriendlyName = (value) => $(`#rm_api_block select option[value="${value}"]`).first().text() || value; | |
| 5754 | - | |
| 5755 | - if (params.apiUsed) { | |
| 5756 | - params.apiUsed = getFriendlyName(params.apiUsed); | |
| 5757 | - } | |
| 5758 | - | |
| 5759 | - if (params.this_main_api) { | |
| 5760 | - params.mainApiFriendlyName = getFriendlyName(params.this_main_api); | |
| 5761 | - } | |
| 5762 | - | |
| 5763 | - if (params.chatInjects) { | |
| 5764 | - params.ActualChatHistoryTokens = params.ActualChatHistoryTokens - params.chatInjects; | |
| 5765 | - } | |
| 5766 | - | |
| 5767 | - if (params.this_main_api == 'openai') { | |
| 5768 | - //for OAI API | |
| 5769 | - //console.log('-- Counting OAI Tokens'); | |
| 5770 | - | |
| 5771 | - //params.finalPromptTokens = itemizedPrompts[thisPromptSet].oaiTotalTokens; | |
| 5772 | - params.oaiMainTokens = itemizedPrompts[thisPromptSet].oaiMainTokens; | |
| 5773 | - params.oaiStartTokens = itemizedPrompts[thisPromptSet].oaiStartTokens; | |
| 5774 | - params.ActualChatHistoryTokens = itemizedPrompts[thisPromptSet].oaiConversationTokens; | |
| 5775 | - params.examplesStringTokens = itemizedPrompts[thisPromptSet].oaiExamplesTokens; | |
| 5776 | - params.oaiPromptTokens = itemizedPrompts[thisPromptSet].oaiPromptTokens - (params.afterScenarioAnchorTokens + params.beforeScenarioAnchorTokens) + params.examplesStringTokens; | |
| 5777 | - params.oaiBiasTokens = itemizedPrompts[thisPromptSet].oaiBiasTokens; | |
| 5778 | - params.oaiJailbreakTokens = itemizedPrompts[thisPromptSet].oaiJailbreakTokens; | |
| 5779 | - params.oaiNudgeTokens = itemizedPrompts[thisPromptSet].oaiNudgeTokens; | |
| 5780 | - params.oaiImpersonateTokens = itemizedPrompts[thisPromptSet].oaiImpersonateTokens; | |
| 5781 | - params.oaiNsfwTokens = itemizedPrompts[thisPromptSet].oaiNsfwTokens; | |
| 5782 | - params.finalPromptTokens = | |
| 5783 | - params.oaiStartTokens + | |
| 5784 | - params.oaiPromptTokens + | |
| 5785 | - params.oaiMainTokens + | |
| 5786 | - params.oaiNsfwTokens + | |
| 5787 | - params.oaiBiasTokens + | |
| 5788 | - params.oaiImpersonateTokens + | |
| 5789 | - params.oaiJailbreakTokens + | |
| 5790 | - params.oaiNudgeTokens + | |
| 5791 | - params.ActualChatHistoryTokens + | |
| 5792 | - //charDescriptionTokens + | |
| 5793 | - //charPersonalityTokens + | |
| 5794 | - //allAnchorsTokens + | |
| 5795 | - params.worldInfoStringTokens + | |
| 5796 | - params.beforeScenarioAnchorTokens + | |
| 5797 | - params.afterScenarioAnchorTokens; | |
| 5798 | - // Max context size - max completion tokens | |
| 5799 | - params.thisPrompt_max_context = (oai_settings.openai_max_context - oai_settings.openai_max_tokens); | |
| 5800 | - | |
| 5801 | - //console.log('-- applying % on OAI tokens'); | |
| 5802 | - params.oaiStartTokensPercentage = ((params.oaiStartTokens / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 5803 | - params.storyStringTokensPercentage = (((params.afterScenarioAnchorTokens + params.beforeScenarioAnchorTokens + params.oaiPromptTokens) / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 5804 | - params.ActualChatHistoryTokensPercentage = ((params.ActualChatHistoryTokens / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 5805 | - params.promptBiasTokensPercentage = ((params.oaiBiasTokens / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 5806 | - params.worldInfoStringTokensPercentage = ((params.worldInfoStringTokens / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 5807 | - params.allAnchorsTokensPercentage = ((params.allAnchorsTokens / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 5808 | - params.selectedTokenizer = getFriendlyTokenizerName(params.this_main_api).tokenizerName; | |
| 5809 | - params.oaiSystemTokens = params.oaiImpersonateTokens + params.oaiJailbreakTokens + params.oaiNudgeTokens + params.oaiStartTokens + params.oaiNsfwTokens + params.oaiMainTokens; | |
| 5810 | - params.oaiSystemTokensPercentage = ((params.oaiSystemTokens / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 5811 | - } else { | |
| 5812 | - //for non-OAI APIs | |
| 5813 | - //console.log('-- Counting non-OAI Tokens'); | |
| 5814 | - params.finalPromptTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].finalPrompt); | |
| 5815 | - params.storyStringTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].storyString) - params.worldInfoStringTokens; | |
| 5816 | - params.examplesStringTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].examplesString); | |
| 5817 | - params.mesSendStringTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].mesSendString); | |
| 5818 | - params.ActualChatHistoryTokens = params.mesSendStringTokens - (params.allAnchorsTokens - (params.beforeScenarioAnchorTokens + params.afterScenarioAnchorTokens)) + power_user.token_padding; | |
| 5819 | - params.instructionTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].instruction); | |
| 5820 | - params.promptBiasTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].promptBias); | |
| 5821 | - | |
| 5822 | - params.totalTokensInPrompt = | |
| 5823 | - params.storyStringTokens + //chardefs total | |
| 5824 | - params.worldInfoStringTokens + | |
| 5825 | - params.examplesStringTokens + // example messages | |
| 5826 | - params.ActualChatHistoryTokens + //chat history | |
| 5827 | - params.allAnchorsTokens + // AN and/or legacy anchors | |
| 5828 | - //afterScenarioAnchorTokens + //only counts if AN is set to 'after scenario' | |
| 5829 | - //zeroDepthAnchorTokens + //same as above, even if AN not on 0 depth | |
| 5830 | - params.promptBiasTokens; //{{}} | |
| 5831 | - //- thisPrompt_padding; //not sure this way of calculating is correct, but the math results in same value as 'finalPrompt' | |
| 5832 | - params.thisPrompt_max_context = itemizedPrompts[thisPromptSet].this_max_context; | |
| 5833 | - params.thisPrompt_actual = params.thisPrompt_max_context - params.thisPrompt_padding; | |
| 5834 | - | |
| 5835 | - //console.log('-- applying % on non-OAI tokens'); | |
| 5836 | - params.storyStringTokensPercentage = ((params.storyStringTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); | |
| 5837 | - params.ActualChatHistoryTokensPercentage = ((params.ActualChatHistoryTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); | |
| 5838 | - params.promptBiasTokensPercentage = ((params.promptBiasTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); | |
| 5839 | - params.worldInfoStringTokensPercentage = ((params.worldInfoStringTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); | |
| 5840 | - params.allAnchorsTokensPercentage = ((params.allAnchorsTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); | |
| 5841 | - params.selectedTokenizer = itemizedPrompts[thisPromptSet]?.tokenizer || getFriendlyTokenizerName(params.this_main_api).tokenizerName; | |
| 5842 | - } | |
| 5843 | - return params; | |
| 5844 | -} | |
| 5845 | - | |
| 5846 | -export function findItemizedPromptSet(itemizedPrompts, incomingMesId) { | |
| 5847 | - var thisPromptSet = undefined; | |
| 5848 | - | |
| 5849 | - for (var i = 0; i < itemizedPrompts.length; i++) { | |
| 5850 | - console.log(`looking for ${incomingMesId} vs ${itemizedPrompts[i].mesId}`); | |
| 5851 | - if (itemizedPrompts[i].mesId === incomingMesId) { | |
| 5852 | - console.log(`found matching mesID ${i}`); | |
| 5853 | - thisPromptSet = i; | |
| 5854 | - PromptArrayItemForRawPromptDisplay = i; | |
| 5855 | - console.log(`wanting to raw display of ArrayItem: ${PromptArrayItemForRawPromptDisplay} which is mesID ${incomingMesId}`); | |
| 5856 | - console.log(itemizedPrompts[thisPromptSet]); | |
| 5857 | - break; | |
| 5858 | - } else if (itemizedPrompts[i].rawPrompt) { | |
| 5859 | - priorPromptArrayItemForRawPromptDisplay = i; | |
| 5860 | - } | |
| 5861 | - } | |
| 5862 | - return thisPromptSet; | |
| 5863 | -} | |
| 5864 | - | |
| 5865 | -async function promptItemize(itemizedPrompts, requestedMesId) { | |
| 5866 | - console.log('PROMPT ITEMIZE ENTERED'); | |
| 5867 | - var incomingMesId = Number(requestedMesId); | |
| 5868 | - console.debug(`looking for MesId ${incomingMesId}`); | |
| 5869 | - var thisPromptSet = findItemizedPromptSet(itemizedPrompts, incomingMesId); | |
| 5870 | - | |
| 5871 | - if (thisPromptSet === undefined) { | |
| 5872 | - console.log(`couldnt find the right mesId. looked for ${incomingMesId}`); | |
| 5873 | - console.log(itemizedPrompts); | |
| 5874 | - return null; | |
| 5875 | - } | |
| 5876 | - | |
| 5877 | - const params = await itemizedParams(itemizedPrompts, thisPromptSet, incomingMesId); | |
| 5878 | - const flatten = (rawPrompt) => Array.isArray(rawPrompt) ? rawPrompt.map(x => x.content).join('\n') : rawPrompt; | |
| 5879 | - | |
| 5880 | - const template = params.this_main_api == 'openai' | |
| 5881 | - ? await renderTemplateAsync('itemizationChat', params) | |
| 5882 | - : await renderTemplateAsync('itemizationText', params); | |
| 5883 | - | |
| 5884 | - const popup = new Popup(template, POPUP_TYPE.TEXT); | |
| 5885 | - | |
| 5886 | - /** @type {HTMLElement} */ | |
| 5887 | - const diffPrevPrompt = popup.dlg.querySelector('#diffPrevPrompt'); | |
| 5888 | - if (priorPromptArrayItemForRawPromptDisplay) { | |
| 5889 | - diffPrevPrompt.style.display = ''; | |
| 5890 | - diffPrevPrompt.addEventListener('click', function () { | |
| 5891 | - const dmp = new DiffMatchPatch(); | |
| 5892 | - const text1 = flatten(itemizedPrompts[priorPromptArrayItemForRawPromptDisplay].rawPrompt); | |
| 5893 | - const text2 = flatten(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt); | |
| 5894 | - | |
| 5895 | - dmp.Diff_Timeout = 2.0; | |
| 5896 | - | |
| 5897 | - const d = dmp.diff_main(text1, text2); | |
| 5898 | - let ds = dmp.diff_prettyHtml(d); | |
| 5899 | - // make it readable | |
| 5900 | - ds = ds.replaceAll('background:#e6ffe6;', 'background:#b9f3b9; color:black;'); | |
| 5901 | - ds = ds.replaceAll('background:#ffe6e6;', 'background:#f5b4b4; color:black;'); | |
| 5902 | - ds = ds.replaceAll('¶', ''); | |
| 5903 | - const container = document.createElement('div'); | |
| 5904 | - container.innerHTML = DOMPurify.sanitize(ds); | |
| 5905 | - const rawPromptWrapper = document.getElementById('rawPromptWrapper'); | |
| 5906 | - rawPromptWrapper.replaceChildren(container); | |
| 5907 | - $('#rawPromptPopup').slideToggle(); | |
| 5908 | - }); | |
| 5909 | - } else { | |
| 5910 | - diffPrevPrompt.style.display = 'none'; | |
| 5911 | - } | |
| 5912 | - popup.dlg.querySelector('#copyPromptToClipboard').addEventListener('pointerup', async function () { | |
| 5913 | - let rawPrompt = itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt; | |
| 5914 | - let rawPromptValues = rawPrompt; | |
| 5915 | - | |
| 5916 | - if (Array.isArray(rawPrompt)) { | |
| 5917 | - rawPromptValues = rawPrompt.map(x => x.content).join('\n'); | |
| 5918 | - } | |
| 5919 | - | |
| 5920 | - await copyText(rawPromptValues); | |
| 5921 | - toastr.info(t`Copied!`); | |
| 5922 | - }); | |
| 5923 | - | |
| 5924 | - popup.dlg.querySelector('#showRawPrompt').addEventListener('click', async function () { | |
| 5925 | - //console.log(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt); | |
| 5926 | - console.log(PromptArrayItemForRawPromptDisplay); | |
| 5927 | - console.log(itemizedPrompts); | |
| 5928 | - console.log(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt); | |
| 5929 | - | |
| 5930 | - const rawPrompt = flatten(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt); | |
| 5931 | - | |
| 5932 | - // Mobile needs special handholding. The side-view on the popup wouldn't work, | |
| 5933 | - // so we just show an additional popup for this. | |
| 5934 | - if (isMobile()) { | |
| 5935 | - const content = document.createElement('div'); | |
| 5936 | - content.classList.add('tokenItemizingMaintext'); | |
| 5937 | - content.innerText = rawPrompt; | |
| 5938 | - const popup = new Popup(content, POPUP_TYPE.TEXT, null, { allowVerticalScrolling: true, leftAlign: true }); | |
| 5939 | - await popup.show(); | |
| 5940 | - return; | |
| 5941 | - } | |
| 5942 | - | |
| 5943 | - //let DisplayStringifiedPrompt = JSON.stringify(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt).replace(/\n+/g, '<br>'); | |
| 5944 | - const rawPromptWrapper = document.getElementById('rawPromptWrapper'); | |
| 5945 | - rawPromptWrapper.innerText = rawPrompt; | |
| 5946 | - $('#rawPromptPopup').slideToggle(); | |
| 5947 | - }); | |
| 5948 | - | |
| 5949 | - await popup.show(); | |
| 5950 | -} | |
| 5951 | - | |
| 5952 | 5647 | function setInContextMessages(msgInContextCount, type) { |
| 5953 | 5648 | $('#chat .mes').removeClass('lastInContext'); |
| 5954 | 5649 | |
| @@ -10474,15 +10169,6 @@ function addDebugFunctions() { | ||
| 10474 | 10169 | const message = await generateRaw(text, null, false, false); |
| 10475 | 10170 | alert(message); |
| 10476 | 10171 | }); |
| 10477 | - | |
| 10478 | - registerDebugFunction('clearPrompts', 'Delete itemized prompts', 'Deletes all itemized prompts from the local storage.', async () => { | |
| 10479 | - await clearItemizedPrompts(); | |
| 10480 | - toastr.info('Itemized prompts deleted.'); | |
| 10481 | - if (getCurrentChatId()) { | |
| 10482 | - await reloadCurrentChat(); | |
| 10483 | - } | |
| 10484 | - }); | |
| 10485 | - | |
| 10486 | 10172 | registerDebugFunction('toggleEventTracing', 'Toggle event tracing', 'Useful to see what triggered a certain event.', () => { |
| 10487 | 10173 | localStorage.setItem('eventTracing', localStorage.getItem('eventTracing') === 'true' ? 'false' : 'true'); |
| 10488 | 10174 | toastr.info('Event tracing is now ' + (localStorage.getItem('eventTracing') === 'true' ? 'enabled' : 'disabled')); |
| @@ -11614,14 +11300,6 @@ jQuery(async function () { | ||
| 11614 | 11300 | } |
| 11615 | 11301 | }); |
| 11616 | 11302 | |
| 11617 | - $(document).on('pointerup', '.mes_prompt', async function () { | |
| 11618 | - let mesIdForItemization = $(this).closest('.mes').attr('mesId'); | |
| 11619 | - console.log(`looking for mesID: ${mesIdForItemization}`); | |
| 11620 | - if (itemizedPrompts.length !== undefined && itemizedPrompts.length !== 0) { | |
| 11621 | - await promptItemize(itemizedPrompts, mesIdForItemization); | |
| 11622 | - } | |
| 11623 | - }); | |
| 11624 | - | |
| 11625 | 11303 | //******************** |
| 11626 | 11304 | //***Message Editor*** |
| 11627 | 11305 | $(document).on('click', '.mes_edit', async function () { |
| @@ -12517,13 +12195,6 @@ jQuery(async function () { | ||
| 12517 | 12195 | // Added here to prevent execution before script.js is loaded and get rid of quirky timeouts |
| 12518 | 12196 | await firstLoadInit(); |
| 12519 | 12197 | |
| 12520 | - eventSource.on(event_types.CHAT_DELETED, async (name) => { | |
| 12521 | - await deleteItemizedPrompts(name); | |
| 12522 | - }); | |
| 12523 | - eventSource.on(event_types.GROUP_CHAT_DELETED, async (name) => { | |
| 12524 | - await deleteItemizedPrompts(name); | |
| 12525 | - }); | |
| 12526 | - | |
| 12527 | 12198 | window.addEventListener('beforeunload', (e) => { |
| 12528 | 12199 | if (isChatSaving) { |
| 12529 | 12200 | e.preventDefault(); |
| @@ -0,0 +1,352 @@ | ||
| 1 | +import { DiffMatchPatch, DOMPurify, localforage } from '../lib.js'; | |
| 2 | +import { chat, event_types, eventSource, getCurrentChatId, reloadCurrentChat } from '../script.js'; | |
| 3 | +import { t } from './i18n.js'; | |
| 4 | +import { oai_settings } from './openai.js'; | |
| 5 | +import { Popup, POPUP_TYPE } from './popup.js'; | |
| 6 | +import { power_user, registerDebugFunction } from './power-user.js'; | |
| 7 | +import { isMobile } from './RossAscends-mods.js'; | |
| 8 | +import { renderTemplateAsync } from './templates.js'; | |
| 9 | +import { getFriendlyTokenizerName, getTokenCountAsync } from './tokenizers.js'; | |
| 10 | +import { copyText } from './utils.js'; | |
| 11 | + | |
| 12 | +let PromptArrayItemForRawPromptDisplay; | |
| 13 | +let priorPromptArrayItemForRawPromptDisplay; | |
| 14 | + | |
| 15 | +const promptStorage = localforage.createInstance({ name: 'SillyTavern_Prompts' }); | |
| 16 | +export let itemizedPrompts = []; | |
| 17 | + | |
| 18 | +/** | |
| 19 | + * Gets the itemized prompts for a chat. | |
| 20 | + * @param {string} chatId Chat ID to load | |
| 21 | + */ | |
| 22 | +export async function loadItemizedPrompts(chatId) { | |
| 23 | + try { | |
| 24 | + if (!chatId) { | |
| 25 | + itemizedPrompts = []; | |
| 26 | + return; | |
| 27 | + } | |
| 28 | + | |
| 29 | + itemizedPrompts = await promptStorage.getItem(chatId); | |
| 30 | + | |
| 31 | + if (!itemizedPrompts) { | |
| 32 | + itemizedPrompts = []; | |
| 33 | + } | |
| 34 | + } catch { | |
| 35 | + console.log('Error loading itemized prompts for chat', chatId); | |
| 36 | + itemizedPrompts = []; | |
| 37 | + } | |
| 38 | +} | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * Saves the itemized prompts for a chat. | |
| 42 | + * @param {string} chatId Chat ID to save itemized prompts for | |
| 43 | + */ | |
| 44 | +export async function saveItemizedPrompts(chatId) { | |
| 45 | + try { | |
| 46 | + if (!chatId) { | |
| 47 | + return; | |
| 48 | + } | |
| 49 | + | |
| 50 | + await promptStorage.setItem(chatId, itemizedPrompts); | |
| 51 | + } catch { | |
| 52 | + console.log('Error saving itemized prompts for chat', chatId); | |
| 53 | + } | |
| 54 | +} | |
| 55 | + | |
| 56 | +/** | |
| 57 | + * Replaces the itemized prompt text for a message. | |
| 58 | + * @param {number} mesId Message ID to get itemized prompt for | |
| 59 | + * @param {string} promptText New raw prompt text | |
| 60 | + * @returns | |
| 61 | + */ | |
| 62 | +export async function replaceItemizedPromptText(mesId, promptText) { | |
| 63 | + if (!Array.isArray(itemizedPrompts)) { | |
| 64 | + itemizedPrompts = []; | |
| 65 | + } | |
| 66 | + | |
| 67 | + const itemizedPrompt = itemizedPrompts.find(x => x.mesId === mesId); | |
| 68 | + | |
| 69 | + if (!itemizedPrompt) { | |
| 70 | + return; | |
| 71 | + } | |
| 72 | + | |
| 73 | + itemizedPrompt.rawPrompt = promptText; | |
| 74 | +} | |
| 75 | + | |
| 76 | +/** | |
| 77 | + * Deletes the itemized prompts for a chat. | |
| 78 | + * @param {string} chatId Chat ID to delete itemized prompts for | |
| 79 | + */ | |
| 80 | +export async function deleteItemizedPrompts(chatId) { | |
| 81 | + try { | |
| 82 | + if (!chatId) { | |
| 83 | + return; | |
| 84 | + } | |
| 85 | + | |
| 86 | + await promptStorage.removeItem(chatId); | |
| 87 | + } catch { | |
| 88 | + console.log('Error deleting itemized prompts for chat', chatId); | |
| 89 | + } | |
| 90 | +} | |
| 91 | + | |
| 92 | +/** | |
| 93 | + * Empties the itemized prompts array and caches. | |
| 94 | + */ | |
| 95 | +export async function clearItemizedPrompts() { | |
| 96 | + try { | |
| 97 | + await promptStorage.clear(); | |
| 98 | + itemizedPrompts = []; | |
| 99 | + } catch { | |
| 100 | + console.log('Error clearing itemized prompts'); | |
| 101 | + } | |
| 102 | +} | |
| 103 | + | |
| 104 | +export async function itemizedParams(itemizedPrompts, thisPromptSet, incomingMesId) { | |
| 105 | + const params = { | |
| 106 | + charDescriptionTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].charDescription), | |
| 107 | + charPersonalityTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].charPersonality), | |
| 108 | + scenarioTextTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].scenarioText), | |
| 109 | + userPersonaStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].userPersona), | |
| 110 | + worldInfoStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].worldInfoString), | |
| 111 | + allAnchorsTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].allAnchors), | |
| 112 | + summarizeStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].summarizeString), | |
| 113 | + authorsNoteStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].authorsNoteString), | |
| 114 | + smartContextStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].smartContextString), | |
| 115 | + beforeScenarioAnchorTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].beforeScenarioAnchor), | |
| 116 | + afterScenarioAnchorTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].afterScenarioAnchor), | |
| 117 | + zeroDepthAnchorTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].zeroDepthAnchor), // TODO: unused | |
| 118 | + thisPrompt_padding: itemizedPrompts[thisPromptSet].padding, | |
| 119 | + this_main_api: itemizedPrompts[thisPromptSet].main_api, | |
| 120 | + chatInjects: await getTokenCountAsync(itemizedPrompts[thisPromptSet].chatInjects), | |
| 121 | + chatVectorsStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].chatVectorsString), | |
| 122 | + dataBankVectorsStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].dataBankVectorsString), | |
| 123 | + modelUsed: chat[incomingMesId]?.extra?.model, | |
| 124 | + apiUsed: chat[incomingMesId]?.extra?.api, | |
| 125 | + presetName: itemizedPrompts[thisPromptSet].presetName || t`(Unknown)`, | |
| 126 | + messagesCount: String(itemizedPrompts[thisPromptSet].messagesCount ?? ''), | |
| 127 | + examplesCount: String(itemizedPrompts[thisPromptSet].examplesCount ?? ''), | |
| 128 | + }; | |
| 129 | + | |
| 130 | + const getFriendlyName = (value) => $(`#rm_api_block select option[value="${value}"]`).first().text() || value; | |
| 131 | + | |
| 132 | + if (params.apiUsed) { | |
| 133 | + params.apiUsed = getFriendlyName(params.apiUsed); | |
| 134 | + } | |
| 135 | + | |
| 136 | + if (params.this_main_api) { | |
| 137 | + params.mainApiFriendlyName = getFriendlyName(params.this_main_api); | |
| 138 | + } | |
| 139 | + | |
| 140 | + if (params.chatInjects) { | |
| 141 | + params.ActualChatHistoryTokens = params.ActualChatHistoryTokens - params.chatInjects; | |
| 142 | + } | |
| 143 | + | |
| 144 | + if (params.this_main_api == 'openai') { | |
| 145 | + //for OAI API | |
| 146 | + //console.log('-- Counting OAI Tokens'); | |
| 147 | + | |
| 148 | + //params.finalPromptTokens = itemizedPrompts[thisPromptSet].oaiTotalTokens; | |
| 149 | + params.oaiMainTokens = itemizedPrompts[thisPromptSet].oaiMainTokens; | |
| 150 | + params.oaiStartTokens = itemizedPrompts[thisPromptSet].oaiStartTokens; | |
| 151 | + params.ActualChatHistoryTokens = itemizedPrompts[thisPromptSet].oaiConversationTokens; | |
| 152 | + params.examplesStringTokens = itemizedPrompts[thisPromptSet].oaiExamplesTokens; | |
| 153 | + params.oaiPromptTokens = itemizedPrompts[thisPromptSet].oaiPromptTokens - (params.afterScenarioAnchorTokens + params.beforeScenarioAnchorTokens) + params.examplesStringTokens; | |
| 154 | + params.oaiBiasTokens = itemizedPrompts[thisPromptSet].oaiBiasTokens; | |
| 155 | + params.oaiJailbreakTokens = itemizedPrompts[thisPromptSet].oaiJailbreakTokens; | |
| 156 | + params.oaiNudgeTokens = itemizedPrompts[thisPromptSet].oaiNudgeTokens; | |
| 157 | + params.oaiImpersonateTokens = itemizedPrompts[thisPromptSet].oaiImpersonateTokens; | |
| 158 | + params.oaiNsfwTokens = itemizedPrompts[thisPromptSet].oaiNsfwTokens; | |
| 159 | + params.finalPromptTokens = | |
| 160 | + params.oaiStartTokens + | |
| 161 | + params.oaiPromptTokens + | |
| 162 | + params.oaiMainTokens + | |
| 163 | + params.oaiNsfwTokens + | |
| 164 | + params.oaiBiasTokens + | |
| 165 | + params.oaiImpersonateTokens + | |
| 166 | + params.oaiJailbreakTokens + | |
| 167 | + params.oaiNudgeTokens + | |
| 168 | + params.ActualChatHistoryTokens + | |
| 169 | + //charDescriptionTokens + | |
| 170 | + //charPersonalityTokens + | |
| 171 | + //allAnchorsTokens + | |
| 172 | + params.worldInfoStringTokens + | |
| 173 | + params.beforeScenarioAnchorTokens + | |
| 174 | + params.afterScenarioAnchorTokens; | |
| 175 | + // Max context size - max completion tokens | |
| 176 | + params.thisPrompt_max_context = (oai_settings.openai_max_context - oai_settings.openai_max_tokens); | |
| 177 | + | |
| 178 | + //console.log('-- applying % on OAI tokens'); | |
| 179 | + params.oaiStartTokensPercentage = ((params.oaiStartTokens / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 180 | + params.storyStringTokensPercentage = (((params.afterScenarioAnchorTokens + params.beforeScenarioAnchorTokens + params.oaiPromptTokens) / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 181 | + params.ActualChatHistoryTokensPercentage = ((params.ActualChatHistoryTokens / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 182 | + params.promptBiasTokensPercentage = ((params.oaiBiasTokens / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 183 | + params.worldInfoStringTokensPercentage = ((params.worldInfoStringTokens / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 184 | + params.allAnchorsTokensPercentage = ((params.allAnchorsTokens / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 185 | + params.selectedTokenizer = getFriendlyTokenizerName(params.this_main_api).tokenizerName; | |
| 186 | + params.oaiSystemTokens = params.oaiImpersonateTokens + params.oaiJailbreakTokens + params.oaiNudgeTokens + params.oaiStartTokens + params.oaiNsfwTokens + params.oaiMainTokens; | |
| 187 | + params.oaiSystemTokensPercentage = ((params.oaiSystemTokens / (params.finalPromptTokens)) * 100).toFixed(2); | |
| 188 | + } else { | |
| 189 | + //for non-OAI APIs | |
| 190 | + //console.log('-- Counting non-OAI Tokens'); | |
| 191 | + params.finalPromptTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].finalPrompt); | |
| 192 | + params.storyStringTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].storyString) - params.worldInfoStringTokens; | |
| 193 | + params.examplesStringTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].examplesString); | |
| 194 | + params.mesSendStringTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].mesSendString); | |
| 195 | + params.ActualChatHistoryTokens = params.mesSendStringTokens - (params.allAnchorsTokens - (params.beforeScenarioAnchorTokens + params.afterScenarioAnchorTokens)) + power_user.token_padding; | |
| 196 | + params.instructionTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].instruction); | |
| 197 | + params.promptBiasTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].promptBias); | |
| 198 | + | |
| 199 | + params.totalTokensInPrompt = | |
| 200 | + params.storyStringTokens + //chardefs total | |
| 201 | + params.worldInfoStringTokens + | |
| 202 | + params.examplesStringTokens + // example messages | |
| 203 | + params.ActualChatHistoryTokens + //chat history | |
| 204 | + params.allAnchorsTokens + // AN and/or legacy anchors | |
| 205 | + //afterScenarioAnchorTokens + //only counts if AN is set to 'after scenario' | |
| 206 | + //zeroDepthAnchorTokens + //same as above, even if AN not on 0 depth | |
| 207 | + params.promptBiasTokens; //{{}} | |
| 208 | + //- thisPrompt_padding; //not sure this way of calculating is correct, but the math results in same value as 'finalPrompt' | |
| 209 | + params.thisPrompt_max_context = itemizedPrompts[thisPromptSet].this_max_context; | |
| 210 | + params.thisPrompt_actual = params.thisPrompt_max_context - params.thisPrompt_padding; | |
| 211 | + | |
| 212 | + //console.log('-- applying % on non-OAI tokens'); | |
| 213 | + params.storyStringTokensPercentage = ((params.storyStringTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); | |
| 214 | + params.ActualChatHistoryTokensPercentage = ((params.ActualChatHistoryTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); | |
| 215 | + params.promptBiasTokensPercentage = ((params.promptBiasTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); | |
| 216 | + params.worldInfoStringTokensPercentage = ((params.worldInfoStringTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); | |
| 217 | + params.allAnchorsTokensPercentage = ((params.allAnchorsTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); | |
| 218 | + params.selectedTokenizer = itemizedPrompts[thisPromptSet]?.tokenizer || getFriendlyTokenizerName(params.this_main_api).tokenizerName; | |
| 219 | + } | |
| 220 | + return params; | |
| 221 | +} | |
| 222 | + | |
| 223 | +export function findItemizedPromptSet(itemizedPrompts, incomingMesId) { | |
| 224 | + let thisPromptSet = undefined; | |
| 225 | + | |
| 226 | + for (let i = 0; i < itemizedPrompts.length; i++) { | |
| 227 | + console.log(`looking for ${incomingMesId} vs ${itemizedPrompts[i].mesId}`); | |
| 228 | + if (itemizedPrompts[i].mesId === incomingMesId) { | |
| 229 | + console.log(`found matching mesID ${i}`); | |
| 230 | + thisPromptSet = i; | |
| 231 | + PromptArrayItemForRawPromptDisplay = i; | |
| 232 | + console.log(`wanting to raw display of ArrayItem: ${PromptArrayItemForRawPromptDisplay} which is mesID ${incomingMesId}`); | |
| 233 | + console.log(itemizedPrompts[thisPromptSet]); | |
| 234 | + break; | |
| 235 | + } else if (itemizedPrompts[i].rawPrompt) { | |
| 236 | + priorPromptArrayItemForRawPromptDisplay = i; | |
| 237 | + } | |
| 238 | + } | |
| 239 | + return thisPromptSet; | |
| 240 | +} | |
| 241 | + | |
| 242 | +export async function promptItemize(itemizedPrompts, requestedMesId) { | |
| 243 | + console.log('PROMPT ITEMIZE ENTERED'); | |
| 244 | + var incomingMesId = Number(requestedMesId); | |
| 245 | + console.debug(`looking for MesId ${incomingMesId}`); | |
| 246 | + var thisPromptSet = findItemizedPromptSet(itemizedPrompts, incomingMesId); | |
| 247 | + | |
| 248 | + if (thisPromptSet === undefined) { | |
| 249 | + console.log(`couldnt find the right mesId. looked for ${incomingMesId}`); | |
| 250 | + console.log(itemizedPrompts); | |
| 251 | + return null; | |
| 252 | + } | |
| 253 | + | |
| 254 | + const params = await itemizedParams(itemizedPrompts, thisPromptSet, incomingMesId); | |
| 255 | + const flatten = (rawPrompt) => Array.isArray(rawPrompt) ? rawPrompt.map(x => x.content).join('\n') : rawPrompt; | |
| 256 | + | |
| 257 | + const template = params.this_main_api == 'openai' | |
| 258 | + ? await renderTemplateAsync('itemizationChat', params) | |
| 259 | + : await renderTemplateAsync('itemizationText', params); | |
| 260 | + | |
| 261 | + const popup = new Popup(template, POPUP_TYPE.TEXT); | |
| 262 | + | |
| 263 | + /** @type {HTMLElement} */ | |
| 264 | + const diffPrevPrompt = popup.dlg.querySelector('#diffPrevPrompt'); | |
| 265 | + if (priorPromptArrayItemForRawPromptDisplay) { | |
| 266 | + diffPrevPrompt.style.display = ''; | |
| 267 | + diffPrevPrompt.addEventListener('click', function () { | |
| 268 | + const dmp = new DiffMatchPatch(); | |
| 269 | + const text1 = flatten(itemizedPrompts[priorPromptArrayItemForRawPromptDisplay].rawPrompt); | |
| 270 | + const text2 = flatten(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt); | |
| 271 | + | |
| 272 | + dmp.Diff_Timeout = 2.0; | |
| 273 | + | |
| 274 | + const d = dmp.diff_main(text1, text2); | |
| 275 | + let ds = dmp.diff_prettyHtml(d); | |
| 276 | + // make it readable | |
| 277 | + ds = ds.replaceAll('background:#e6ffe6;', 'background:#b9f3b9; color:black;'); | |
| 278 | + ds = ds.replaceAll('background:#ffe6e6;', 'background:#f5b4b4; color:black;'); | |
| 279 | + ds = ds.replaceAll('¶', ''); | |
| 280 | + const container = document.createElement('div'); | |
| 281 | + container.innerHTML = DOMPurify.sanitize(ds); | |
| 282 | + const rawPromptWrapper = document.getElementById('rawPromptWrapper'); | |
| 283 | + rawPromptWrapper.replaceChildren(container); | |
| 284 | + $('#rawPromptPopup').slideToggle(); | |
| 285 | + }); | |
| 286 | + } else { | |
| 287 | + diffPrevPrompt.style.display = 'none'; | |
| 288 | + } | |
| 289 | + popup.dlg.querySelector('#copyPromptToClipboard').addEventListener('pointerup', async function () { | |
| 290 | + let rawPrompt = itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt; | |
| 291 | + let rawPromptValues = rawPrompt; | |
| 292 | + | |
| 293 | + if (Array.isArray(rawPrompt)) { | |
| 294 | + rawPromptValues = rawPrompt.map(x => x.content).join('\n'); | |
| 295 | + } | |
| 296 | + | |
| 297 | + await copyText(rawPromptValues); | |
| 298 | + toastr.info(t`Copied!`); | |
| 299 | + }); | |
| 300 | + | |
| 301 | + popup.dlg.querySelector('#showRawPrompt').addEventListener('click', async function () { | |
| 302 | + //console.log(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt); | |
| 303 | + console.log(PromptArrayItemForRawPromptDisplay); | |
| 304 | + console.log(itemizedPrompts); | |
| 305 | + console.log(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt); | |
| 306 | + | |
| 307 | + const rawPrompt = flatten(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt); | |
| 308 | + | |
| 309 | + // Mobile needs special handholding. The side-view on the popup wouldn't work, | |
| 310 | + // so we just show an additional popup for this. | |
| 311 | + if (isMobile()) { | |
| 312 | + const content = document.createElement('div'); | |
| 313 | + content.classList.add('tokenItemizingMaintext'); | |
| 314 | + content.innerText = rawPrompt; | |
| 315 | + const popup = new Popup(content, POPUP_TYPE.TEXT, null, { allowVerticalScrolling: true, leftAlign: true }); | |
| 316 | + await popup.show(); | |
| 317 | + return; | |
| 318 | + } | |
| 319 | + | |
| 320 | + //let DisplayStringifiedPrompt = JSON.stringify(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt).replace(/\n+/g, '<br>'); | |
| 321 | + const rawPromptWrapper = document.getElementById('rawPromptWrapper'); | |
| 322 | + rawPromptWrapper.innerText = rawPrompt; | |
| 323 | + $('#rawPromptPopup').slideToggle(); | |
| 324 | + }); | |
| 325 | + | |
| 326 | + await popup.show(); | |
| 327 | +} | |
| 328 | + | |
| 329 | +export function initItemizedPrompts() { | |
| 330 | + registerDebugFunction('clearPrompts', 'Delete itemized prompts', 'Deletes all itemized prompts from the local storage.', async () => { | |
| 331 | + await clearItemizedPrompts(); | |
| 332 | + toastr.info('Itemized prompts deleted.'); | |
| 333 | + if (getCurrentChatId()) { | |
| 334 | + await reloadCurrentChat(); | |
| 335 | + } | |
| 336 | + }); | |
| 337 | + | |
| 338 | + $(document).on('pointerup', '.mes_prompt', async function () { | |
| 339 | + let mesIdForItemization = $(this).closest('.mes').attr('mesId'); | |
| 340 | + console.log(`looking for mesID: ${mesIdForItemization}`); | |
| 341 | + if (itemizedPrompts.length !== undefined && itemizedPrompts.length !== 0) { | |
| 342 | + await promptItemize(itemizedPrompts, mesIdForItemization); | |
| 343 | + } | |
| 344 | + }); | |
| 345 | + | |
| 346 | + eventSource.on(event_types.CHAT_DELETED, async (name) => { | |
| 347 | + await deleteItemizedPrompts(name); | |
| 348 | + }); | |
| 349 | + eventSource.on(event_types.GROUP_CHAT_DELETED, async (name) => { | |
| 350 | + await deleteItemizedPrompts(name); | |
| 351 | + }); | |
| 352 | +} | |