Add prompt suppression and FIFO
This commit is contained in:
parent
b396bb818d
commit
9165480dfb
|
@ -529,7 +529,11 @@ aside.menu.main-menu .menu-expanse {
|
||||||
.chat-message.summarized {
|
.chat-message.summarized {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
.chat-message.suppress .message-body {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
.tool-drawer, .tool-drawer-mask {
|
.tool-drawer, .tool-drawer-mask {
|
||||||
|
z-index: 1;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
width: 0%;
|
width: 0%;
|
||||||
|
|
|
@ -154,8 +154,10 @@
|
||||||
|
|
||||||
let response: Response
|
let response: Response
|
||||||
|
|
||||||
|
const messageFilter = (m) => !m.suppress && m.role !== 'error' && m.content && !m.summarized
|
||||||
|
|
||||||
// Submit only the role and content of the messages, provide the previous messages as well for context
|
// Submit only the role and content of the messages, provide the previous messages as well for context
|
||||||
const filtered = messages.filter((message) => message.role !== 'error' && message.content && !message.summarized)
|
let filtered = messages.filter(messageFilter)
|
||||||
|
|
||||||
// Get an estimate of the total prompt size we're sending
|
// Get an estimate of the total prompt size we're sending
|
||||||
const promptTokenCount:number = countPromptTokens(filtered, model)
|
const promptTokenCount:number = countPromptTokens(filtered, model)
|
||||||
|
@ -176,7 +178,8 @@
|
||||||
const systemPad = (filtered[0] || {} as Message).role === 'system' ? 1 : 0
|
const systemPad = (filtered[0] || {} as Message).role === 'system' ? 1 : 0
|
||||||
const mlen = filtered.length - systemPad // always keep system prompt
|
const mlen = filtered.length - systemPad // always keep system prompt
|
||||||
let diff = mlen - (pinTop + pinBottom)
|
let diff = mlen - (pinTop + pinBottom)
|
||||||
while (diff <= 3 && (pinTop > 0 || pinBottom > 1)) {
|
const useRollMode = !prepareSummaryPrompt(chatId, 0)
|
||||||
|
while (!useRollMode && diff <= 3 && (pinTop > 0 || pinBottom > 1)) {
|
||||||
// Not enough prompts exposed to summarize
|
// Not enough prompts exposed to summarize
|
||||||
// try to open up pinTop and pinBottom to see if we can get more to summarize
|
// try to open up pinTop and pinBottom to see if we can get more to summarize
|
||||||
if (pinTop === 1 && pinBottom > 1) {
|
if (pinTop === 1 && pinBottom > 1) {
|
||||||
|
@ -188,7 +191,7 @@
|
||||||
}
|
}
|
||||||
diff = mlen - (pinTop + pinBottom)
|
diff = mlen - (pinTop + pinBottom)
|
||||||
}
|
}
|
||||||
if (diff > 0) {
|
if (!useRollMode && diff > 0) {
|
||||||
// We've found at least one prompt we can try to summarize
|
// We've found at least one prompt we can try to summarize
|
||||||
// Reduce to prompts we'll send in for summary
|
// Reduce to prompts we'll send in for summary
|
||||||
// (we may need to update this to not include the pin-top, but the context it provides seems to help in the accuracy of the summary)
|
// (we may need to update this to not include the pin-top, but the context it provides seems to help in the accuracy of the summary)
|
||||||
|
@ -197,6 +200,7 @@
|
||||||
let sourceTokenCount = countPromptTokens(summarize, model)
|
let sourceTokenCount = countPromptTokens(summarize, model)
|
||||||
// build summary prompt message
|
// build summary prompt message
|
||||||
let summaryPrompt = prepareSummaryPrompt(chatId, sourceTokenCount)
|
let summaryPrompt = prepareSummaryPrompt(chatId, sourceTokenCount)
|
||||||
|
|
||||||
const summaryMessage = {
|
const summaryMessage = {
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: summaryPrompt
|
content: summaryPrompt
|
||||||
|
@ -279,8 +283,23 @@
|
||||||
} else if (sourceTokenCount <= 20) {
|
} else if (sourceTokenCount <= 20) {
|
||||||
addMessage(chatId, { role: 'error', content: 'Unable to summarize. Not enough words in past content to summarize.', uuid: uuidv4() })
|
addMessage(chatId, { role: 'error', content: 'Unable to summarize. Not enough words in past content to summarize.', uuid: uuidv4() })
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!useRollMode && diff < 1) {
|
||||||
addMessage(chatId, { role: 'error', content: 'Unable to summarize. Not enough messages in past content to summarize.', uuid: uuidv4() })
|
addMessage(chatId, { role: 'error', content: 'Unable to summarize. Not enough messages in past content to summarize.', uuid: uuidv4() })
|
||||||
|
} else {
|
||||||
|
// roll-off mode
|
||||||
|
const top = filtered.slice(0,pinTop+systemPad)
|
||||||
|
let rollaway = filtered.slice(pinTop+systemPad)
|
||||||
|
let promptTokenCount = countPromptTokens(top.concat(rollaway), model)
|
||||||
|
// suppress messages we're rolling off
|
||||||
|
while (rollaway.length > (((promptTokenCount + (chatSettings.max_tokens||1)) > maxTokens) ? pinBottom||1 : 1)
|
||||||
|
&& promptTokenCount >= chatSettings.summaryThreshold) {
|
||||||
|
const rollOff = rollaway.shift()
|
||||||
|
if (rollOff) rollOff.suppress = true
|
||||||
|
promptTokenCount = countPromptTokens(top.concat(rollaway), model)
|
||||||
|
}
|
||||||
|
saveChatStore()
|
||||||
|
// get a new list now excluding them
|
||||||
|
filtered = messages.filter(messageFilter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Code from './Code.svelte'
|
import Code from './Code.svelte'
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
import { createEventDispatcher, onMount } from 'svelte'
|
||||||
import { deleteMessage, chatsStorage, deleteSummaryMessage, truncateFromMessage, submitExitingPromptsNow } from './Storage.svelte'
|
import { deleteMessage, chatsStorage, deleteSummaryMessage, truncateFromMessage, submitExitingPromptsNow, saveChatStore } from './Storage.svelte'
|
||||||
import { getPrice } from './Stats.svelte'
|
import { getPrice } from './Stats.svelte'
|
||||||
import SvelteMarkdown from 'svelte-markdown'
|
import SvelteMarkdown from 'svelte-markdown'
|
||||||
import type { Message, Model, Chat } from './Types.svelte'
|
import type { Message, Model, Chat } from './Types.svelte'
|
||||||
import Fa from 'svelte-fa/src/fa.svelte'
|
import Fa from 'svelte-fa/src/fa.svelte'
|
||||||
import { faTrash, faDiagramPredecessor, faDiagramNext, faCircleCheck, faPaperPlane } from '@fortawesome/free-solid-svg-icons/index'
|
import { faTrash, faDiagramPredecessor, faDiagramNext, faCircleCheck, faPaperPlane, faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons/index'
|
||||||
import { scrollIntoViewWithOffset } from './Util.svelte'
|
import { scrollIntoViewWithOffset } from './Util.svelte'
|
||||||
|
|
||||||
export let message:Message
|
export let message:Message
|
||||||
|
@ -155,6 +155,28 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let waitingForSuppressConfirm:any = 0
|
||||||
|
|
||||||
|
const setSuppress = (value:boolean) => {
|
||||||
|
// clearTimeout(waitingForSuppressConfirm); waitingForSuppressConfirm = 0
|
||||||
|
// if (value && !waitingForSuppressConfirm) {
|
||||||
|
// // wait a second for another click to avoid accidental deletes
|
||||||
|
// waitingForSuppressConfirm = setTimeout(() => { waitingForSuppressConfirm = 0 }, 1000)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// clearTimeout(waitingForSuppressConfirm)
|
||||||
|
waitingForTruncateConfirm = 0
|
||||||
|
if (message.summarized) {
|
||||||
|
// is in a summary, so we're summarized
|
||||||
|
window.alert('Sorry, you can\'t suppress a summarized message')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.suppress = value
|
||||||
|
saveChatStore()
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#key message.uuid}
|
{#key message.uuid}
|
||||||
|
@ -168,6 +190,7 @@
|
||||||
class:user-message={message.role === 'user' || message.role === 'system'}
|
class:user-message={message.role === 'user' || message.role === 'system'}
|
||||||
class:assistant-message={message.role === 'error' || message.role === 'assistant'}
|
class:assistant-message={message.role === 'error' || message.role === 'assistant'}
|
||||||
class:summarized={message.summarized}
|
class:summarized={message.summarized}
|
||||||
|
class:suppress={message.suppress}
|
||||||
class:editing={editing}
|
class:editing={editing}
|
||||||
>
|
>
|
||||||
<div class="message-body content">
|
<div class="message-body content">
|
||||||
|
@ -259,6 +282,24 @@
|
||||||
{/if}
|
{/if}
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if !message.summarized && message.role !== 'system'}
|
||||||
|
<a
|
||||||
|
href={'#'}
|
||||||
|
title={(message.suppress ? 'Uns' : 'S') + 'uppress message from submission'}
|
||||||
|
class=" msg-delete-button button is-small is-info"
|
||||||
|
on:click|preventDefault={() => {
|
||||||
|
setSuppress(!message.suppress)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{#if waitingForSuppressConfirm}
|
||||||
|
<span class="icon"><Fa icon={faCircleCheck} /></span>
|
||||||
|
{:else if message.suppress}
|
||||||
|
<span class="icon"><Fa icon={faEye} /></span>
|
||||||
|
{:else}
|
||||||
|
<span class="icon"><Fa icon={faEyeSlash} /></span>
|
||||||
|
{/if}
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#each messages as message, i}
|
{#each messages as message, i}
|
||||||
{#if !(message.summarized && $globalStorage.hideSummarized) && !(i === 0 && message.role === 'system' && !chatSettings.useSystemPrompt)}
|
{#if !((message.summarized) && $globalStorage.hideSummarized) && !(i === 0 && message.role === 'system' && !chatSettings.useSystemPrompt)}
|
||||||
<EditMessage bind:message={message} chatId={chatId} />
|
<EditMessage bind:message={message} chatId={chatId} />
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
@ -100,7 +100,10 @@ const profileSetting: ChatSetting & SettingSelect = {
|
||||||
afterChange: (chatId, setting) => {
|
afterChange: (chatId, setting) => {
|
||||||
applyProfile(chatId, '', !getChat(chatId).sessionStarted)
|
applyProfile(chatId, '', !getChat(chatId).sessionStarted)
|
||||||
return true // Signal we should refresh the setting modal
|
return true // Signal we should refresh the setting modal
|
||||||
}
|
},
|
||||||
|
setDefault: (chatId, setting, value) => {
|
||||||
|
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settings that will not be part of the API request
|
// Settings that will not be part of the API request
|
||||||
|
@ -159,16 +162,16 @@ const nonRequestSettings: ChatSetting[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'useSummarization',
|
key: 'useSummarization',
|
||||||
name: 'Enable Auto Summarize',
|
name: 'Enable Continuous Chat',
|
||||||
header: 'Continuous Chat - Summarization',
|
header: 'Continuous Chat - (Summarize or FIFO)',
|
||||||
headerClass: 'is-info',
|
headerClass: 'is-info',
|
||||||
title: 'When out of token space, summarize past tokens and keep going.',
|
title: 'When out of token space, summarize or remove past prompts and keep going.',
|
||||||
type: 'boolean'
|
type: 'boolean'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'summaryThreshold',
|
key: 'summaryThreshold',
|
||||||
name: 'Summary Threshold',
|
name: 'Token Threshold',
|
||||||
title: 'When prompt history breaks this threshold, past prompts will be summarized to create space. 0 to disable.',
|
title: 'When prompt history breaks this threshold, past prompts will be summarized or rolled off to create space.',
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 32000,
|
max: 32000,
|
||||||
step: 1,
|
step: 1,
|
||||||
|
@ -178,7 +181,7 @@ const nonRequestSettings: ChatSetting[] = [
|
||||||
{
|
{
|
||||||
key: 'summarySize',
|
key: 'summarySize',
|
||||||
name: 'Max Summary Size',
|
name: 'Max Summary Size',
|
||||||
title: 'Maximum number of tokens to use for summarization response.',
|
title: 'Maximum number of tokens allowed for summary response.',
|
||||||
min: 128,
|
min: 128,
|
||||||
max: 2048,
|
max: 2048,
|
||||||
step: 1,
|
step: 1,
|
||||||
|
@ -187,7 +190,7 @@ const nonRequestSettings: ChatSetting[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'pinTop',
|
key: 'pinTop',
|
||||||
name: 'Keep First Prompts During Summary',
|
name: 'Keep First Prompts',
|
||||||
title: 'When we run out of space and need to summarize prompts, the top number of prompts will not be removed after summarization.',
|
title: 'When we run out of space and need to summarize prompts, the top number of prompts will not be removed after summarization.',
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 4,
|
max: 4,
|
||||||
|
@ -198,7 +201,7 @@ const nonRequestSettings: ChatSetting[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'pinBottom',
|
key: 'pinBottom',
|
||||||
name: 'Exclude Bottom Prompts From Summary',
|
name: 'Exclude Bottom Prompts',
|
||||||
title: 'When we run out of space and need to summarize prompts, do not summarize the the last number prompts you set here.',
|
title: 'When we run out of space and need to summarize prompts, do not summarize the the last number prompts you set here.',
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 20, // Will be auto adjusted down if needs more
|
max: 20, // Will be auto adjusted down if needs more
|
||||||
|
@ -209,7 +212,7 @@ const nonRequestSettings: ChatSetting[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'summaryPrompt',
|
key: 'summaryPrompt',
|
||||||
name: 'Summary Generation Prompt',
|
name: 'Summary Generation Prompt (Empty will use FIFO instead.)',
|
||||||
title: 'A prompt used to summarize past prompts.',
|
title: 'A prompt used to summarize past prompts.',
|
||||||
placeholder: 'Enter a prompt that will be used to summarize past prompts here.',
|
placeholder: 'Enter a prompt that will be used to summarize past prompts here.',
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
removed?: boolean;
|
removed?: boolean;
|
||||||
summarized?: string[];
|
summarized?: string[];
|
||||||
summary?: string[];
|
summary?: string[];
|
||||||
|
suppress?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Request = {
|
export type Request = {
|
||||||
|
@ -41,7 +42,6 @@
|
||||||
frequency_penalty?: number;
|
frequency_penalty?: number;
|
||||||
logit_bias?: Record<string, any> | null;
|
logit_bias?: Record<string, any> | null;
|
||||||
user?: string;
|
user?: string;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ChatSettings = {
|
export type ChatSettings = {
|
||||||
|
@ -154,6 +154,7 @@ type SettingBoolean = {
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
hide?: (chatId:number) => boolean;
|
hide?: (chatId:number) => boolean;
|
||||||
apiTransform?: (chatId:number, setting:ChatSetting, value:any) => any;
|
apiTransform?: (chatId:number, setting:ChatSetting, value:any) => any;
|
||||||
|
setDefault?: (chatId:number, setting:ChatSetting, value:any) => any;
|
||||||
beforeChange?: (chatId:number, setting:ChatSetting, value:any) => boolean;
|
beforeChange?: (chatId:number, setting:ChatSetting, value:any) => boolean;
|
||||||
afterChange?: (chatId:number, setting:ChatSetting, value:any) => boolean;
|
afterChange?: (chatId:number, setting:ChatSetting, value:any) => boolean;
|
||||||
} & (SettingNumber | SettingSelect | SettingBoolean | SettingText | SettingTextArea | SettingOther);
|
} & (SettingNumber | SettingSelect | SettingBoolean | SettingText | SettingTextArea | SettingOther);
|
||||||
|
|
Loading…
Reference in New Issue