diff --git a/common/adapters.ts b/common/adapters.ts index f5eb8e078..6767d1ab6 100644 --- a/common/adapters.ts +++ b/common/adapters.ts @@ -291,6 +291,7 @@ export const adapterSettings: { swipesPerGeneration: ['aphrodite'], epsilonCutoff: ['aphrodite'], etaCutoff: ['aphrodite'], + prependAuthorNameToMessages: ['openai'], prefill: ['claude'], diff --git a/common/presets.ts b/common/presets.ts index 88dbbd193..4a4e8f67b 100644 --- a/common/presets.ts +++ b/common/presets.ts @@ -71,6 +71,7 @@ export const presetValidator = { streamResponse: 'boolean?', ultimeJailbreak: 'string?', prefixNameAppend: 'boolean?', + prependAuthorNameToMessages: 'boolean?', prefill: 'string?', antiBond: 'boolean?', diff --git a/common/presets/openai.ts b/common/presets/openai.ts index 49e159a2d..4d5202407 100644 --- a/common/presets/openai.ts +++ b/common/presets/openai.ts @@ -27,6 +27,7 @@ Facts: {{memory}} Relevant Information: {{user_embed}} `, + prependAuthorNameToMessages: true, }, openaiAlt: { name: 'Turbo (#2)', @@ -52,6 +53,7 @@ Facts: {{memory}} Relevant Information: {{user_embed}} `, + prependAuthorNameToMessages: true, }, openaiTurbo: { name: 'DaVinci', @@ -74,5 +76,6 @@ Description of {{char}}: {{personality}} Circumstances and context of the dialogue: {{scenario}} Facts: {{memory}}`, + prependAuthorNameToMessages: true, }, } satisfies Record> diff --git a/common/types/schema.ts b/common/types/schema.ts index 50022f7c4..685cbe400 100644 --- a/common/types/schema.ts +++ b/common/types/schema.ts @@ -519,6 +519,7 @@ export namespace AppSchema { promptOrder?: Array<{ placeholder: string; enabled: boolean }> ultimeJailbreak?: string prefixNameAppend?: boolean + prependAuthorNameToMessages?: boolean prefill?: string ignoreCharacterUjb?: boolean antiBond?: boolean diff --git a/srv/adapter/chat-completion.ts b/srv/adapter/chat-completion.ts index a67a9d012..13b07ae9d 100644 --- a/srv/adapter/chat-completion.ts +++ b/srv/adapter/chat-completion.ts @@ -26,6 +26,7 @@ type SplitSampleChatProps = { char: string sender: string budget?: number + prependAuthorNameToMessages: boolean } type CompletionContent = Array<{ finish_reason: string; index: number } & ({ text: string } | T)> @@ -249,15 +250,28 @@ export async function toChatCompletionPayload( const line = all[i] - const obj: CompletionItem = { - role: 'assistant', - content: line.trim().replace(BOT_REPLACE, replyAs.name).replace(SELF_REPLACE, handle), - } - const isSystem = line.startsWith('System:') const isUser = line.startsWith(handle) const isBot = !isUser && !isSystem + const lineWithPholdersReplaced = line + .trim() + .replace(BOT_REPLACE, replyAs.name) + .replace(SELF_REPLACE, handle) + + const author = isBot ? replyAs.name : isUser ? handle : undefined + + const prependAuthorNameToMessages = opts.gen.prependAuthorNameToMessages ?? true + + const content = prependAuthorNameToMessages + ? lineWithPholdersReplaced + : lineWithPholdersReplaced.replace(author ? `${author}: ` : '', '') + + const obj: CompletionItem = { + role: 'assistant', + content, + } + const insert = inserts.get(distanceFromBottom) if (insert) history.push({ role: 'system', content: insert }) @@ -270,6 +284,7 @@ export async function toChatCompletionPayload( sampleChat: obj.content, char: replyAs.name, sender: handle, + prependAuthorNameToMessages: opts.gen.prependAuthorNameToMessages ?? true, }) if (tokens + consumed > maxBudget) { @@ -307,7 +322,7 @@ export async function toChatCompletionPayload( } export async function splitSampleChat(opts: SplitSampleChatProps) { - const { sampleChat, char, sender, budget } = opts + const { sampleChat, char, sender, budget, prependAuthorNameToMessages } = opts const regex = new RegExp( `(?<=\\n)(?=${escapeRegex(char)}:|${escapeRegex(sender)}:|System:|)`, 'gi' @@ -339,10 +354,17 @@ export async function splitSampleChat(opts: SplitSampleChatProps) { ? 'user' : 'system' - const msg: CompletionItem = { - role: role, - content: sample.replace(BOT_REPLACE, char).replace(SELF_REPLACE, sender), - } + const sampleWithPholdersReplaced = sample + .replace(BOT_REPLACE, char) + .replace(SELF_REPLACE, sender) + + const author = role === 'assistant' ? char : role === 'user' ? sender : undefined + + const content = prependAuthorNameToMessages + ? sampleWithPholdersReplaced + : sampleWithPholdersReplaced.replace(author ? `${author}: ` : '', '') + + const msg: CompletionItem = { role, content } const length = await encoder()(msg.content) if (budget && tokens + length > budget) break diff --git a/tests/chat-model-sample-chat.spec.ts b/tests/chat-model-sample-chat.spec.ts index 2b0cf0481..5711ccd1b 100644 --- a/tests/chat-model-sample-chat.spec.ts +++ b/tests/chat-model-sample-chat.spec.ts @@ -95,6 +95,7 @@ async function testInput(input: string, budget?: number) { char: TEST_CHARACTER_NAME, sender: TEST_USER_NAME, budget, + prependAuthorNameToMessages: true, }) return JSON.stringify(result.additions, null, 2) diff --git a/web/shared/GenerationSettings.tsx b/web/shared/GenerationSettings.tsx index c92df27e3..33f4e9abd 100644 --- a/web/shared/GenerationSettings.tsx +++ b/web/shared/GenerationSettings.tsx @@ -575,6 +575,21 @@ const PromptSettings: Component< hide={useAdvanced() === 'basic'} showTemplates /> + + For OpenAI Chat Completion. Prepends messages with the name of their author. + Recommended for multi-character and multi-user chats. + + } + value={props.inherit?.prependAuthorNameToMessages ?? true} + disabled={props.disabled} + service={props.service} + format={props.format} + aiSetting={'prependAuthorNameToMessages'} + />