|
382 | 382 | color:var(--color-text);
|
383 | 383 | }
|
384 | 384 | html.nockoffAI #context-order-desc,
|
| 385 | +html.nockoffAI #contextTokensTable, |
385 | 386 | html.nockoffAI .modal-desc {
|
386 | 387 | color:var(--color-base-80);
|
387 | 388 | }
|
|
699 | 700 | html.nockoffAI .SelectBox > select:disabled {
|
700 | 701 | background: var(--color-disabled);
|
701 | 702 | }
|
| 703 | +.relative { |
| 704 | + position: relative; |
| 705 | +} |
702 | 706 |
|
703 | 707 | .Checkbox {
|
704 | 708 | user-select: none;
|
|
796 | 800 | top: 1.45em;
|
797 | 801 | right: 5px;
|
798 | 802 | }
|
| 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 | +} |
799 | 814 | button:hover {
|
800 | 815 | background: var(--color-base-40);
|
801 | 816 | }
|
|
2008 | 2023 | <${InputBox} label="Suffix" type="text" placeholder="[/INST]"
|
2009 | 2024 | readOnly=${!!cancel} value=${memoryTokens.suffix} onValueChange=${(value) => handleMemoryTokensChange("suffix", value)}/>
|
2010 | 2025 | </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> |
2019 | 2039 | </${Modal}>`;
|
2020 | 2040 | }
|
2021 | 2041 |
|
|
2037 | 2057 | <${InputBox} label="AN Injection Depth (0-N)" type="number" step="1"
|
2038 | 2058 | readOnly=${!!cancel} value=${authorNoteDepth} onValueChange=${handleAuthorNoteDepthChange}/>
|
2039 | 2059 | </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> |
2048 | 2073 | </${Modal}>`;
|
2049 | 2074 | }
|
2050 | 2075 |
|
2051 |
| -function ContextModal({ isOpen, closeModal, memoryTokens, handleMemoryTokensChange, modifiedPrompt, defaultPresets, cancel }) { |
| 2076 | +function ContextModal({ isOpen, closeModal, tokens, memoryTokens, authorNoteTokens, handleMemoryTokensChange, modifiedPrompt, defaultPresets, cancel }) { |
2052 | 2077 | return html`
|
2053 | 2078 | <${Modal} isOpen=${isOpen} onClose=${closeModal}
|
2054 | 2079 | title="Context"
|
2055 | 2080 | 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> |
2056 | 2107 | <${CollapsibleGroup} label="Advanced Context Ordering">
|
2057 | 2108 | <div id="context-order-desc">
|
2058 | 2109 | You can use the following placeholders to order the context according to your needs:<br />
|
|
3556 | 3607 | const sessionReconnectTimer = useRef();
|
3557 | 3608 | const useScrollSmoothing = useRef(true);
|
3558 | 3609 | const [templates, setTemplates] = useDBTemplates(defaultPresets.instructTemplates);
|
| 3610 | + const [templateReplacements, setTemplateReplacements] = useState(false); |
3559 | 3611 | const [templatesImport, setTemplatesImport] = useState(false);
|
3560 | 3612 | const [selectedTemplate, setSelectedTemplate] = useSessionState('template', "Llama 3");
|
3561 | 3613 | const [chatMode, setChatMode] = useSessionState('chatMode', false);
|
|
3616 | 3668 | const [authorNoteDepth, setAuthorNoteDepth] = useSessionState('authorNoteDepth', defaultPresets.authorNoteDepth);
|
3617 | 3669 | const [worldInfo, setWorldInfo] = useSessionState('worldInfo', defaultPresets.worldInfo);
|
3618 | 3670 |
|
| 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 | + |
3619 | 3698 | // AN and Memory
|
3620 | 3699 | function handleauthorNoteTokensChange(key,value) {
|
3621 | 3700 | setAuthorNoteTokens((prevauthorNoteTokens) => ({ ...prevauthorNoteTokens, [key]: value }));
|
3622 | 3701 | }
|
| 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 | + |
3623 | 3739 | function handleMemoryTokensChange(key,value) {
|
3624 | 3740 | setMemoryTokens((prevMemoryTokens) => ({ ...prevMemoryTokens, [key]: value }));
|
3625 | 3741 | }
|
| 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 | + |
3626 | 3816 |
|
3627 | 3817 |
|
3628 | 3818 | const insertTemplate = (sysInst) => {
|
|
3667 | 3857 | onInput({ target: elem });
|
3668 | 3858 | }
|
3669 | 3859 |
|
3670 |
| - |
3671 | 3860 | const toggleModal = (modalKey) => {
|
3672 | 3861 | setModalState((prevState) => ({
|
3673 | 3862 | ...prevState,
|
|
3789 | 3978 | // replaced, (3) instruct template placeholders are replaced (4) non-empty
|
3790 | 3979 | // lines are joined back together.
|
3791 | 3980 | 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) |
3797 | 3982 | }).filter(function (line) {
|
3798 | 3983 | return line.trim() !== "";
|
3799 | 3984 | }).join("\n").replace(/\\n/g, '\n');
|
|
3802 | 3987 | }, [contextLength, promptText, memoryTokens, authorNoteTokens, authorNoteDepth, assembledWorldInfo, worldInfo.prefix, worldInfo.suffix]);
|
3803 | 3988 |
|
3804 | 3989 | 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); |
3827 | 3991 | }, [additionalContextPrompt, templates, selectedTemplate]);
|
3828 | 3992 |
|
3829 | 3993 | async function predict(prompt = modifiedPrompt, chunkCount = promptChunks.length) {
|
|
4154 | 4318 | }, 500);
|
4155 | 4319 | ac.signal.addEventListener('abort', () => clearTimeout(to));
|
4156 | 4320 | return () => ac.abort();
|
4157 |
| - }, [promptText, cancel, endpoint, endpointAPI]); |
| 4321 | + }, [modalState["context"], promptText, cancel, endpoint, endpointAPI]); |
4158 | 4322 |
|
4159 | 4323 | useEffect(() => {
|
4160 | 4324 | if (endpointAPI != 3)
|
|
4762 | 4926 | </${CollapsibleGroup}>
|
4763 | 4927 | <${CollapsibleGroup} label="Persistent Context">
|
4764 | 4928 | <label className="TextArea">
|
4765 |
| - Memory |
| 4929 | + <div>Memory ${memoryTokens.tokens > 0 ? html`<small>(${memoryTokens.tokens} Tokens)</small>`:""}</div> |
4766 | 4930 | <textarea
|
4767 | 4931 | readOnly=${!!cancel}
|
4768 | 4932 | placeholder="Anything written here will be injected at the head of the prompt. Tokens here DO count towards the Context Limit."
|
|
4774 | 4938 | className="textAreaSettings"
|
4775 | 4939 | disabled=${!!cancel}
|
4776 | 4940 | onClick=${() => toggleModal("memory")}>
|
4777 |
| -
|
4778 | 4941 | <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>
|
4779 | 4942 | </button>
|
4780 | 4943 | </label>
|
4781 | 4944 | <label className="TextArea">
|
4782 |
| - Author's Note |
| 4945 | + <div>Author's Note ${authorNoteTokens.tokens > 0 ? html`<small>(${authorNoteTokens.tokens} Tokens)</small>`:""}</div> |
4783 | 4946 | <textarea
|
4784 | 4947 | readOnly=${!!cancel}
|
4785 | 4948 | placeholder="Anything written here will be injected ${authorNoteDepth} newlines from bottom into context."
|
|
4913 | 5076 | <${ContextModal}
|
4914 | 5077 | isOpen=${modalState.context}
|
4915 | 5078 | closeModal=${() => closeModal("context")}
|
| 5079 | + tokens=${tokens} |
4916 | 5080 | memoryTokens=${memoryTokens}
|
| 5081 | + authorNoteTokens=${authorNoteTokens} |
4917 | 5082 | handleMemoryTokensChange=${handleMemoryTokensChange}
|
4918 | 5083 | modifiedPrompt=${modifiedPrompt}
|
4919 | 5084 | defaultPresets=${defaultPresets}
|
|
0 commit comments