Skip to content

Commit 9278fff

Browse files
authored
Merge pull request #68 from neCo2/persistent-context-token-counts
Feature/Persistent Context Token Counts
2 parents 486bf54 + 41ff87b commit 9278fff

File tree

1 file changed

+214
-49
lines changed

1 file changed

+214
-49
lines changed

mikupad.html

+214-49
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@
382382
color:var(--color-text);
383383
}
384384
html.nockoffAI #context-order-desc,
385+
html.nockoffAI #contextTokensTable,
385386
html.nockoffAI .modal-desc {
386387
color:var(--color-base-80);
387388
}
@@ -699,6 +700,9 @@
699700
html.nockoffAI .SelectBox > select:disabled {
700701
background: var(--color-disabled);
701702
}
703+
.relative {
704+
position: relative;
705+
}
702706

703707
.Checkbox {
704708
user-select: none;
@@ -796,6 +800,17 @@
796800
top: 1.45em;
797801
right: 5px;
798802
}
803+
.token-counter {
804+
pointer-events: none;
805+
position:absolute;
806+
bottom:0;
807+
right:0;
808+
transform: translate(0%,-50%);
809+
color: var(--color-base-50);
810+
background: color-mix(in srgb, var(--color-base-30), transparent 50%);
811+
}.token-counter::after {
812+
content:" Tokens";
813+
}
799814
button:hover {
800815
background: var(--color-base-40);
801816
}
@@ -2008,14 +2023,19 @@
20082023
<${InputBox} label="Suffix" type="text" placeholder="[/INST]"
20092024
readOnly=${!!cancel} value=${memoryTokens.suffix} onValueChange=${(value) => handleMemoryTokensChange("suffix", value)}/>
20102025
</div>
2011-
<textarea
2012-
readOnly=${!!cancel}
2013-
placeholder="Anything written here will be injected at the head of the prompt. Tokens here DO count towards the Context Limit."
2014-
defaultValue=${memoryTokens.text}
2015-
value=${memoryTokens.text}
2016-
onInput=${(e) => handleMemoryTokensChange("text", e.target.value) }
2017-
class="expanded-text-area-settings"
2018-
id="memory-area-settings"/>
2026+
<div class="relative">
2027+
<textarea
2028+
readOnly=${!!cancel}
2029+
placeholder="Anything written here will be injected at the head of the prompt. Tokens here DO count towards the Context Limit."
2030+
defaultValue=${memoryTokens.text}
2031+
value=${memoryTokens.text}
2032+
onInput=${(e) => handleMemoryTokensChange("text", e.target.value) }
2033+
class="expanded-text-area-settings"
2034+
id="memory-area-settings"/>
2035+
<div class="token-counter">
2036+
${memoryTokens.tokens}
2037+
</div>
2038+
</div>
20192039
</${Modal}>`;
20202040
}
20212041

@@ -2037,22 +2057,53 @@
20372057
<${InputBox} label="AN Injection Depth (0-N)" type="number" step="1"
20382058
readOnly=${!!cancel} value=${authorNoteDepth} onValueChange=${handleAuthorNoteDepthChange}/>
20392059
</div>
2040-
<textarea
2041-
readOnly=${!!cancel}
2042-
placeholder="Anything written here will be injected ${authorNoteDepth} newlines from bottom into context."
2043-
defaultValue=${authorNoteTokens.text}
2044-
value=${authorNoteTokens.text}
2045-
onInput=${(e) => handleauthorNoteTokensChange("text", e.target.value) }
2046-
class="expanded-text-area-settings"
2047-
id="expanded-an-settings"/>
2060+
<div class="relative">
2061+
<textarea
2062+
readOnly=${!!cancel}
2063+
placeholder="Anything written here will be injected ${authorNoteDepth} newlines from bottom into context."
2064+
defaultValue=${authorNoteTokens.text}
2065+
value=${authorNoteTokens.text}
2066+
onInput=${(e) => handleauthorNoteTokensChange("text", e.target.value) }
2067+
class="expanded-text-area-settings"
2068+
id="expanded-an-settings"/>
2069+
<div class="token-counter">
2070+
${authorNoteTokens.tokens}
2071+
</div>
2072+
</div>
20482073
</${Modal}>`;
20492074
}
20502075

2051-
function ContextModal({ isOpen, closeModal, memoryTokens, handleMemoryTokensChange, modifiedPrompt, defaultPresets, cancel }) {
2076+
function ContextModal({ isOpen, closeModal, tokens, memoryTokens, authorNoteTokens, handleMemoryTokensChange, modifiedPrompt, defaultPresets, cancel }) {
20522077
return html`
20532078
<${Modal} isOpen=${isOpen} onClose=${closeModal}
20542079
title="Context"
20552080
description="This is the prompt being sent to your large language model.">
2081+
<div id="advancedContextPlaceholders">
2082+
<table id="contextTokensTable" border="1" frame="void" rules="all">
2083+
<thead>
2084+
<tr>
2085+
<th></th>
2086+
<th>Memory</th>
2087+
<th>World Info</th>
2088+
<th>Author's Note</th>
2089+
<th>Prompt</th>
2090+
<th></th>
2091+
<th>Total</th>
2092+
</tr>
2093+
</thead>
2094+
<tbody>
2095+
<tr>
2096+
<th>Tokens</th>
2097+
<td>${memoryTokens.tokens}</td>
2098+
<td>${memoryTokens.tokensWI}</td>
2099+
<td>${authorNoteTokens.tokens}</td>
2100+
<td>${tokens - authorNoteTokens.tokens - memoryTokens.tokensWI - memoryTokens.tokens}</td>
2101+
<td></td>
2102+
<td>${tokens}</td>
2103+
</tr>
2104+
</tbody>
2105+
</table>
2106+
</div>
20562107
<${CollapsibleGroup} label="Advanced Context Ordering">
20572108
<div id="context-order-desc">
20582109
You can use the following placeholders to order the context according to your needs:<br />
@@ -3556,6 +3607,7 @@
35563607
const sessionReconnectTimer = useRef();
35573608
const useScrollSmoothing = useRef(true);
35583609
const [templates, setTemplates] = useDBTemplates(defaultPresets.instructTemplates);
3610+
const [templateReplacements, setTemplateReplacements] = useState(false);
35593611
const [templatesImport, setTemplatesImport] = useState(false);
35603612
const [selectedTemplate, setSelectedTemplate] = useSessionState('template', "Llama 3");
35613613
const [chatMode, setChatMode] = useSessionState('chatMode', false);
@@ -3616,13 +3668,151 @@
36163668
const [authorNoteDepth, setAuthorNoteDepth] = useSessionState('authorNoteDepth', defaultPresets.authorNoteDepth);
36173669
const [worldInfo, setWorldInfo] = useSessionState('worldInfo', defaultPresets.worldInfo);
36183670

3671+
3672+
function replacePlaceholders(string,placeholders) {
3673+
// give placeholders as json object
3674+
// { "placeholder":"replacement" }
3675+
return string.replace(/\{[^}]+\}/g, function (placeholder) {
3676+
return placeholders.hasOwnProperty(placeholder)
3677+
? placeholders[placeholder]
3678+
: placeholder;
3679+
}).replace(/\\n/g, '\n')
3680+
};
3681+
useMemo(() => {
3682+
setTemplateReplacements({
3683+
"{inst}": templates[selectedTemplate]?.instPre && templates[selectedTemplate]?.instPre !== ""
3684+
? templates[selectedTemplate]?.instPre
3685+
: "",
3686+
"{/inst}": templates[selectedTemplate]?.instSuf && templates[selectedTemplate]?.instSuf !== ""
3687+
? templates[selectedTemplate]?.instSuf
3688+
: "",
3689+
"{sys}": templates[selectedTemplate]?.sysPre && templates[selectedTemplate]?.sysPre !== ""
3690+
? templates[selectedTemplate]?.sysPre
3691+
: "",
3692+
"{/sys}": templates[selectedTemplate]?.sysSuf && templates[selectedTemplate]?.sysSuf !== ""
3693+
? templates[selectedTemplate]?.sysSuf
3694+
: "",
3695+
})
3696+
}, [selectedTemplate,templates])
3697+
36193698
// AN and Memory
36203699
function handleauthorNoteTokensChange(key,value) {
36213700
setAuthorNoteTokens((prevauthorNoteTokens) => ({ ...prevauthorNoteTokens, [key]: value }));
36223701
}
3702+
// token counts for an
3703+
useEffect(() => {
3704+
const order = ["prefix","text","suffix"]
3705+
const assembled = authorNoteTokens.text && authorNoteTokens.text !== ""
3706+
? order.map(key => authorNoteTokens[key]).join("")
3707+
: "";
3708+
if (assembled == "" || endpointAPI == 3) {
3709+
setAuthorNoteTokens((prevauthorNoteTokens) => ({ ...prevauthorNoteTokens, "tokens": 0 }))
3710+
return
3711+
}
3712+
const ac = new AbortController();
3713+
const to = setTimeout(async () => {
3714+
try {
3715+
const tokenCount = await getTokenCount({
3716+
endpoint,
3717+
endpointAPI,
3718+
...(endpointAPI == 3 || endpointAPI == 0 ? { endpointAPIKey } : {}),
3719+
content: `${replacePlaceholders(assembled,templateReplacements)}`,
3720+
signal: ac.signal,
3721+
...(isMikupadEndpoint ? { proxyEndpoint: sessionStorage.proxyEndpoint } : {})
3722+
});
3723+
setAuthorNoteTokens((prevauthorNoteTokens) => ({
3724+
...prevauthorNoteTokens,
3725+
"tokens": tokenCount - 1
3726+
}));
3727+
} catch (e) {
3728+
if (e.name !== 'AbortError'){
3729+
reportError(e);
3730+
setAuthorNoteTokens((prevauthorNoteTokens) => ({ ...prevauthorNoteTokens, "tokens": 0 }))
3731+
}
3732+
}
3733+
}, 500);
3734+
3735+
ac.signal.addEventListener('abort', () => clearTimeout(to));
3736+
return () => ac.abort();
3737+
},[modalState["context"],authorNoteTokens.text,authorNoteTokens.prefix,authorNoteTokens.suffix,cancel,endpoint,endpointAPI])
3738+
36233739
function handleMemoryTokensChange(key,value) {
36243740
setMemoryTokens((prevMemoryTokens) => ({ ...prevMemoryTokens, [key]: value }));
36253741
}
3742+
// token counts for memory
3743+
useEffect(() => {
3744+
const order = ["prefix","text","suffix"]
3745+
const assembled = memoryTokens.text && memoryTokens.text !== ""
3746+
? order.map(key => memoryTokens[key]).join("")
3747+
: "";
3748+
if (assembled == "" || endpointAPI == 3){
3749+
setMemoryTokens((prevMemoryTokens) => ({ ...prevMemoryTokens, "tokens": 0 }));
3750+
return
3751+
}
3752+
3753+
const ac = new AbortController();
3754+
const to = setTimeout(async () => {
3755+
try {
3756+
const tokenCount = await getTokenCount({
3757+
endpoint,
3758+
endpointAPI,
3759+
...(endpointAPI == 3 || endpointAPI == 0 ? { endpointAPIKey } : {}),
3760+
content: `${replacePlaceholders(assembled,templateReplacements)}`,
3761+
signal: ac.signal,
3762+
...(isMikupadEndpoint ? { proxyEndpoint: sessionStorage.proxyEndpoint } : {})
3763+
});
3764+
setMemoryTokens((prevMemoryTokens) => ({
3765+
...prevMemoryTokens,
3766+
"tokens": tokenCount - 1
3767+
}));
3768+
} catch (e) {
3769+
if (e.name !== 'AbortError'){
3770+
reportError(e);
3771+
setMemoryTokens((prevMemoryTokens) => ({ ...prevMemoryTokens, "tokens": 0 }));
3772+
}
3773+
}
3774+
}, 500);
3775+
3776+
ac.signal.addEventListener('abort', () => clearTimeout(to));
3777+
return () => ac.abort();
3778+
},[modalState["context"],memoryTokens.text,memoryTokens.prefix,memoryTokens.suffix,cancel,endpoint,endpointAPI])
3779+
// token counts for wi
3780+
useEffect(() => {
3781+
const assembled = memoryTokens.worldInfo && memoryTokens.worldInfo !== ""
3782+
? [worldInfo.prefix,memoryTokens.worldInfo,worldInfo.suffix].join("")
3783+
: "";
3784+
if (assembled == "" || endpointAPI == 3){
3785+
setMemoryTokens((prevMemoryTokens) => ({ ...prevMemoryTokens, "tokensWI": 0 }));
3786+
return
3787+
}
3788+
3789+
const ac = new AbortController();
3790+
const to = setTimeout(async () => {
3791+
try {
3792+
const tokenCount = await getTokenCount({
3793+
endpoint,
3794+
endpointAPI,
3795+
...(endpointAPI == 3 || endpointAPI == 0 ? { endpointAPIKey } : {}),
3796+
content: `${replacePlaceholders(assembled,templateReplacements)}`,
3797+
signal: ac.signal,
3798+
...(isMikupadEndpoint ? { proxyEndpoint: sessionStorage.proxyEndpoint } : {})
3799+
});
3800+
setMemoryTokens((prevMemoryTokens) => ({
3801+
...prevMemoryTokens,
3802+
"tokensWI": tokenCount - 1
3803+
}));
3804+
} catch (e) {
3805+
if (e.name !== 'AbortError'){
3806+
reportError(e);
3807+
setMemoryTokens((prevMemoryTokens) => ({ ...prevMemoryTokens, "tokensWI": 0 }));
3808+
}
3809+
}
3810+
}, 500);
3811+
3812+
ac.signal.addEventListener('abort', () => clearTimeout(to));
3813+
return () => ac.abort();
3814+
},[modalState["context"],worldInfo.prefix,memoryTokens.worldInfo,worldInfo.suffix,cancel,endpoint,endpointAPI])
3815+
36263816

36273817

36283818
const insertTemplate = (sysInst) => {
@@ -3667,7 +3857,6 @@
36673857
onInput({ target: elem });
36683858
}
36693859

3670-
36713860
const toggleModal = (modalKey) => {
36723861
setModalState((prevState) => ({
36733862
...prevState,
@@ -3789,11 +3978,7 @@
37893978
// replaced, (3) instruct template placeholders are replaced (4) non-empty
37903979
// lines are joined back together.
37913980
const permContextPrompt = workingContextOrder.split("\n").map(function (line) {
3792-
return line.replace(/\{[^}]+\}/g, function (placeholder) {
3793-
return contextReplacements.hasOwnProperty(placeholder)
3794-
? contextReplacements[placeholder]
3795-
: placeholder;
3796-
});
3981+
return replacePlaceholders(line,contextReplacements)
37973982
}).filter(function (line) {
37983983
return line.trim() !== "";
37993984
}).join("\n").replace(/\\n/g, '\n');
@@ -3802,28 +3987,7 @@
38023987
}, [contextLength, promptText, memoryTokens, authorNoteTokens, authorNoteDepth, assembledWorldInfo, worldInfo.prefix, worldInfo.suffix]);
38033988

38043989
const modifiedPrompt = useMemo(() => {
3805-
const templateReplacements = {
3806-
"{inst}": templates[selectedTemplate]?.instPre && templates[selectedTemplate]?.instPre !== ""
3807-
? templates[selectedTemplate]?.instPre
3808-
: "",
3809-
"{/inst}": templates[selectedTemplate]?.instSuf && templates[selectedTemplate]?.instSuf !== ""
3810-
? templates[selectedTemplate]?.instSuf
3811-
: "",
3812-
"{sys}": templates[selectedTemplate]?.sysPre && templates[selectedTemplate]?.sysPre !== ""
3813-
? templates[selectedTemplate]?.sysPre
3814-
: "",
3815-
"{/sys}": templates[selectedTemplate]?.sysSuf && templates[selectedTemplate]?.sysSuf !== ""
3816-
? templates[selectedTemplate]?.sysSuf
3817-
: "",
3818-
}
3819-
const finalPrompt = additionalContextPrompt
3820-
.replace(/\{[^}]+\}/g, function (placeholder) {
3821-
return templateReplacements.hasOwnProperty(placeholder)
3822-
? templateReplacements[placeholder]
3823-
: placeholder;
3824-
}).replace(/\\n/g, '\n');
3825-
3826-
return finalPrompt;
3990+
return replacePlaceholders(additionalContextPrompt,templateReplacements);
38273991
}, [additionalContextPrompt, templates, selectedTemplate]);
38283992

38293993
async function predict(prompt = modifiedPrompt, chunkCount = promptChunks.length) {
@@ -4154,7 +4318,7 @@
41544318
}, 500);
41554319
ac.signal.addEventListener('abort', () => clearTimeout(to));
41564320
return () => ac.abort();
4157-
}, [promptText, cancel, endpoint, endpointAPI]);
4321+
}, [modalState["context"], promptText, cancel, endpoint, endpointAPI]);
41584322

41594323
useEffect(() => {
41604324
if (endpointAPI != 3)
@@ -4762,7 +4926,7 @@
47624926
</${CollapsibleGroup}>
47634927
<${CollapsibleGroup} label="Persistent Context">
47644928
<label className="TextArea">
4765-
Memory
4929+
<div>Memory ${memoryTokens.tokens > 0 ? html`<small>(${memoryTokens.tokens} Tokens)</small>`:""}</div>
47664930
<textarea
47674931
readOnly=${!!cancel}
47684932
placeholder="Anything written here will be injected at the head of the prompt. Tokens here DO count towards the Context Limit."
@@ -4774,12 +4938,11 @@
47744938
className="textAreaSettings"
47754939
disabled=${!!cancel}
47764940
onClick=${() => toggleModal("memory")}>
4777-
47784941
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="-1 -5 8 7" xmlns="http://www.w3.org/2000/svg"><path d="M0 0 3-3C3-4 3-5 5-5L4-4 5-3 6-4C6-2 5-2 4-2L1 1C0 2-1 1 0 0"></path></svg>
47794942
</button>
47804943
</label>
47814944
<label className="TextArea">
4782-
Author's Note
4945+
<div>Author's Note ${authorNoteTokens.tokens > 0 ? html`<small>(${authorNoteTokens.tokens} Tokens)</small>`:""}</div>
47834946
<textarea
47844947
readOnly=${!!cancel}
47854948
placeholder="Anything written here will be injected ${authorNoteDepth} newlines from bottom into context."
@@ -4913,7 +5076,9 @@
49135076
<${ContextModal}
49145077
isOpen=${modalState.context}
49155078
closeModal=${() => closeModal("context")}
5079+
tokens=${tokens}
49165080
memoryTokens=${memoryTokens}
5081+
authorNoteTokens=${authorNoteTokens}
49175082
handleMemoryTokensChange=${handleMemoryTokensChange}
49185083
modifiedPrompt=${modifiedPrompt}
49195084
defaultPresets=${defaultPresets}

0 commit comments

Comments
 (0)