From e9dab4a973859b6125115a46a3e2e6aa78be130d Mon Sep 17 00:00:00 2001 From: Webifi Date: Fri, 9 Jun 2023 09:45:53 -0500 Subject: [PATCH 1/5] Keep suggested chat name short --- src/lib/Chat.svelte | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib/Chat.svelte b/src/lib/Chat.svelte index 8a45a81..eee7ee2 100644 --- a/src/lib/Chat.svelte +++ b/src/lib/Chat.svelte @@ -555,7 +555,7 @@ const suggestName = async (): Promise => { const suggestMessage: Message = { role: 'user', - content: "Can you give me a 5 word summary of this conversation's topic?", + content: "Using appropriate language, please give a 5 word summary of this conversation's topic.", uuid: uuidv4() } @@ -565,7 +565,9 @@ const response = await sendRequest(suggestMessages, { chat, autoAddMessages: false, - streaming: false + streaming: false, + summaryRequest: true, + maxTokens: 10 }) await response.promiseToFinish() @@ -577,10 +579,10 @@ }) } else { response.getMessages().forEach(m => { - chat.name = m.content + const name = m.content.split(/\s+/).slice(0, 8).join(' ').trim() + if (name) chat.name = name }) saveChatStore() - $checkStateChange++ } } From 3cb56e9477e8936503d8837b985a9349d6476c3d Mon Sep 17 00:00:00 2001 From: Webifi Date: Fri, 9 Jun 2023 09:46:19 -0500 Subject: [PATCH 2/5] Add editing chat name from menu --- src/app.scss | 17 +++++++++-- src/lib/ChatMenuItem.svelte | 59 ++++++++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/src/app.scss b/src/app.scss index ca1f4be..c7d2a98 100644 --- a/src/app.scss +++ b/src/app.scss @@ -231,16 +231,16 @@ $modal-background-background-color-dark: rgba($dark, 0.86) !default; // remove t .menu-list { a:hover { - .delete-button { + .delete-button, .edit-button { display: block !important; background-color: initial; } } - .delete-button { + .delete-button, .edit-button { opacity: .8; } - .delete-button:hover { + .delete-button:hover, .edit-button { opacity: 1; } } @@ -321,6 +321,17 @@ $modal-background-background-color-dark: rgba($dark, 0.86) !default; // remove t z-index: 200; } +.chat-menu-item .edit-button { + position: absolute; + right: 2em; + z-index: 200; +} + +.chat-name-editor { + margin: .5em; + padding:.1em; +} + /* Overrides for main layout */ .side-bar-column { diff --git a/src/lib/ChatMenuItem.svelte b/src/lib/ChatMenuItem.svelte index d4eeb93..4503042 100644 --- a/src/lib/ChatMenuItem.svelte +++ b/src/lib/ChatMenuItem.svelte @@ -1,19 +1,52 @@
  • - { $pinMainMenu = false }} class:is-waiting={waitingForConfirm} class:is-disabled={!$apiKeyStorage} class:is-active={activeChatId === chat.id}> + {#if editing} +
  • \ No newline at end of file From ac7d99948f24aa45489221612ee9673247fa4d6b Mon Sep 17 00:00:00 2001 From: Webifi Date: Fri, 9 Jun 2023 17:21:01 -0500 Subject: [PATCH 3/5] Add hidden prompt prefix setting --- src/lib/Chat.svelte | 22 +++++++++++++++------- src/lib/Profiles.svelte | 17 ++++++++++------- src/lib/Settings.svelte | 9 +++++++++ src/lib/Types.svelte | 2 +- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/lib/Chat.svelte b/src/lib/Chat.svelte index eee7ee2..efa6e87 100644 --- a/src/lib/Chat.svelte +++ b/src/lib/Chat.svelte @@ -24,7 +24,7 @@ } from './Types.svelte' import Prompts from './Prompts.svelte' import Messages from './Messages.svelte' - import { prepareSummaryPrompt, restartProfile } from './Profiles.svelte' + import { mergeProfileFields, prepareSummaryPrompt, restartProfile } from './Profiles.svelte' import { afterUpdate, onMount, onDestroy } from 'svelte' import Fa from 'svelte-fa/src/fa.svelte' @@ -188,6 +188,8 @@ let summarySize = chatSettings.summarySize + const hiddenPromptPrefix = mergeProfileFields(chatSettings, chatSettings.hiddenPromptPrefix).trim() + // console.log('Estimated',promptTokenCount,'prompt token for this request') if (chatSettings.continuousChat && !opts.didSummary && @@ -342,7 +344,14 @@ try { const request: Request = { - messages: filtered.map(m => { return { role: m.role, content: m.content } }) as Message[], + messages: filtered.map((m, i) => { + const r = { role: m.role, content: m.content } + if (i === filtered.length - 1 && m.role === 'user' && hiddenPromptPrefix && !opts.summaryRequest) { + // If the last prompt is a user prompt, and we have a hiddenPromptPrefix, inject it + r.content = hiddenPromptPrefix + '\n\n' + m.content + } + return r + }) as Message[], // Provide the settings by mapping the settingsMap to key/value pairs ...getRequestSettingList().reduce((acc, setting) => { @@ -351,16 +360,15 @@ if (typeof setting.apiTransform === 'function') { value = setting.apiTransform(chatId, setting, value) } - if (opts.summaryRequest && opts.maxTokens) { - // requesting summary. do overrides - if (key === 'max_tokens') value = opts.maxTokens // only as large as we need for summary - if (key === 'n') value = 1 // never more than one completion for summary + if (opts.maxTokens) { + if (key === 'max_tokens') value = opts.maxTokens // only as large as requested } - if (opts.streaming) { + if (opts.streaming || opts.summaryRequest) { /* Streaming goes insane with more than one completion. Doesn't seem like there's any way to separate the jumbled mess of deltas for the different completions. + Summary should only have one completion */ if (key === 'n') value = 1 } diff --git a/src/lib/Profiles.svelte b/src/lib/Profiles.svelte index c899c97..92d0d66 100644 --- a/src/lib/Profiles.svelte +++ b/src/lib/Profiles.svelte @@ -70,22 +70,25 @@ export const getProfile = (key:string, forReset:boolean = false):ChatSettings => return clone } +export const mergeProfileFields = (settings: ChatSettings, content: string|undefined, maxWords: number|undefined = undefined): string => { + if (!content?.toString) return '' + content = (content + '').replaceAll('[[CHARACTER_NAME]]', settings.characterName || 'ChatGPT') + if (maxWords) content = (content + '').replaceAll('[[MAX_WORDS]]', maxWords.toString()) + return content +} + export const prepareProfilePrompt = (chatId:number) => { const settings = getChatSettings(chatId) - const characterName = settings.characterName - const currentProfilePrompt = settings.systemPrompt - return currentProfilePrompt.replaceAll('[[CHARACTER_NAME]]', characterName) + return mergeProfileFields(settings, settings.systemPrompt).trim() } export const prepareSummaryPrompt = (chatId:number, promptsSize:number, maxTokens:number|undefined = undefined) => { const settings = getChatSettings(chatId) - const characterName = settings.characterName || 'ChatGPT' maxTokens = maxTokens || settings.summarySize maxTokens = Math.min(Math.floor(promptsSize / 4), maxTokens) // Make sure we're shrinking by at least a 4th const currentSummaryPrompt = settings.summaryPrompt - return currentSummaryPrompt - .replaceAll('[[CHARACTER_NAME]]', characterName) - .replaceAll('[[MAX_WORDS]]', Math.floor(maxTokens * 0.75).toString()) // ~.75 words per token. May need to reduce + // ~.75 words per token. May need to reduce + return mergeProfileFields(settings, currentSummaryPrompt, Math.floor(maxTokens * 0.75)).trim() } // Restart currently loaded profile diff --git a/src/lib/Settings.svelte b/src/lib/Settings.svelte index a77dea6..4c4e437 100644 --- a/src/lib/Settings.svelte +++ b/src/lib/Settings.svelte @@ -84,6 +84,7 @@ const defaults:ChatSettings = { systemPrompt: '', autoStartSession: false, trainingPrompts: [], + hiddenPromptPrefix: '', // useResponseAlteration: false, // responseAlterations: [], isDirty: false @@ -167,6 +168,14 @@ const systemPromptSettings: ChatSetting[] = [ type: 'textarea', hide: (chatId) => !getChatSettings(chatId).useSystemPrompt }, + { + key: 'hiddenPromptPrefix', + name: 'Hidden Prompt Prefix', + title: 'A prompt that will be silently injected before every user prompt.', + placeholder: 'Enter user prompt prefix here. You can remind ChatGPT how to act.', + type: 'textarea', + hide: (chatId) => !getChatSettings(chatId).useSystemPrompt + }, { key: 'trainingPrompts', name: 'Training Prompts', diff --git a/src/lib/Types.svelte b/src/lib/Types.svelte index 3bd41de..7eabc94 100644 --- a/src/lib/Types.svelte +++ b/src/lib/Types.svelte @@ -58,7 +58,6 @@ profileName: string, profileDescription: string, continuousChat: (''|'fifo'|'summary'); - // useSummarization: boolean; summaryThreshold: number; summarySize: number; pinTop: number; @@ -67,6 +66,7 @@ useSystemPrompt: boolean; systemPrompt: string; autoStartSession: boolean; + hiddenPromptPrefix: string; trainingPrompts?: Message[]; useResponseAlteration?: boolean; responseAlterations?: ResponseAlteration[]; From 15e988758f464d3d5395cf40598778f4775dc422 Mon Sep 17 00:00:00 2001 From: Webifi Date: Fri, 9 Jun 2023 17:47:19 -0500 Subject: [PATCH 4/5] Count hiddenPromptPrefix tokens --- src/lib/Chat.svelte | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lib/Chat.svelte b/src/lib/Chat.svelte index efa6e87..088722f 100644 --- a/src/lib/Chat.svelte +++ b/src/lib/Chat.svelte @@ -37,7 +37,7 @@ faLightbulb, faCommentSlash } from '@fortawesome/free-solid-svg-icons/index' - // import { encode } from 'gpt-tokenizer' + import { encode } from 'gpt-tokenizer' import { v4 as uuidv4 } from 'uuid' import { countPromptTokens, getModelMaxTokens, getPrice } from './Stats.svelte' import { autoGrowInputOnEvent, scrollToMessage, sizeTextElements } from './Util.svelte' @@ -184,11 +184,15 @@ let filtered = messages.filter(messageFilter) // Get an estimate of the total prompt size we're sending - const promptTokenCount:number = countPromptTokens(filtered, model) + let promptTokenCount:number = countPromptTokens(filtered, model) let summarySize = chatSettings.summarySize const hiddenPromptPrefix = mergeProfileFields(chatSettings, chatSettings.hiddenPromptPrefix).trim() + + if (hiddenPromptPrefix && filtered.length && filtered[filtered.length - 1].role === 'user') { + promptTokenCount += encode(hiddenPromptPrefix + '\n\n').length + } // console.log('Estimated',promptTokenCount,'prompt token for this request') From f56317bb8ae849a6cc947a74fe613f91a79fbfd0 Mon Sep 17 00:00:00 2001 From: Webifi Date: Fri, 9 Jun 2023 18:37:07 -0500 Subject: [PATCH 5/5] Improve error handling --- src/lib/Chat.svelte | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/lib/Chat.svelte b/src/lib/Chat.svelte index 088722f..b54a54a 100644 --- a/src/lib/Chat.svelte +++ b/src/lib/Chat.svelte @@ -191,6 +191,7 @@ const hiddenPromptPrefix = mergeProfileFields(chatSettings, chatSettings.hiddenPromptPrefix).trim() if (hiddenPromptPrefix && filtered.length && filtered[filtered.length - 1].role === 'user') { + // update estimate with hiddenPromptPrefix token count promptTokenCount += encode(hiddenPromptPrefix + '\n\n').length } @@ -346,17 +347,21 @@ } } + const messagePayload = filtered.map((m, i) => { + const r = { role: m.role, content: m.content } + if (i === filtered.length - 1 && m.role === 'user' && hiddenPromptPrefix && !opts.summaryRequest) { + // If the last prompt is a user prompt, and we have a hiddenPromptPrefix, inject it + r.content = hiddenPromptPrefix + '\n\n' + m.content + } + return r + }) as Message[] + + // Update token count with actual + promptTokenCount = countPromptTokens(messagePayload, model) + try { const request: Request = { - messages: filtered.map((m, i) => { - const r = { role: m.role, content: m.content } - if (i === filtered.length - 1 && m.role === 'user' && hiddenPromptPrefix && !opts.summaryRequest) { - // If the last prompt is a user prompt, and we have a hiddenPromptPrefix, inject it - r.content = hiddenPromptPrefix + '\n\n' + m.content - } - return r - }) as Message[], - + messages: messagePayload, // Provide the settings by mapping the settingsMap to key/value pairs ...getRequestSettingList().reduce((acc, setting) => { const key = setting.key @@ -403,7 +408,11 @@ let errorResponse try { const errObj = await response.json() - errorResponse = errObj?.error?.code || 'Unexpected Response' + errorResponse = errObj?.error?.code + if (!errorResponse && response.choices && response.choices[0]) { + errorResponse = response.choices[0]?.message?.content + } + errorResponse = errorResponse || 'Unexpected Response' } catch (e) { errorResponse = 'Unknown Response' }