mirror of
				https://github.com/SillyTavern/SillyTavern.git
				synced 2025-06-05 21:59:27 +02:00 
			
		
		
		
	Add per-character system prompt overrides
This commit is contained in:
		| @@ -205,12 +205,12 @@ | |||||||
|         "UI Theme Preset":"UI Theme Preset", |         "UI Theme Preset":"UI Theme Preset", | ||||||
|         "Power User Options":"Power User Options", |         "Power User Options":"Power User Options", | ||||||
|         "Swipes":"Swipes", |         "Swipes":"Swipes", | ||||||
|         "Background Sound Only":"Background Sound Only", |         "Background Sound Only":"BG Sound Only", | ||||||
|         "Auto-load Last Chat":"Auto-load Last Chat", |         "Auto-load Last Chat":"Auto-load Last Chat", | ||||||
|         "Auto-save Message Edits":"Auto-save Message Edits", |         "Auto-save Message Edits":"Auto-save Chat Edits", | ||||||
|         "Auto-fix Markdown":"Auto-fix Markdown", |         "Auto-fix Markdown":"Auto-fix Markdown", | ||||||
|         "Allow {{char}}: in bot messages":"Allow {{char}}: in bot messages", |         "Allow {{char}}: in bot messages":"Show {{char}} in messages", | ||||||
|         "Allow {{user}}: in bot messages":"Allow {{user}}: in bot messages", |         "Allow {{user}}: in bot messages":"Show {{user}} in messages", | ||||||
|         "Auto-scroll Chat":"Auto-scroll Chat", |         "Auto-scroll Chat":"Auto-scroll Chat", | ||||||
|         "Render Formulas":"Render Formulas", |         "Render Formulas":"Render Formulas", | ||||||
|         "Send on Enter":"Send on Enter", |         "Send on Enter":"Send on Enter", | ||||||
|   | |||||||
| @@ -1882,6 +1882,20 @@ | |||||||
|                                 </label> |                                 </label> | ||||||
|                             </div> |                             </div> | ||||||
|                             <div> |                             <div> | ||||||
|  |                                 <label for="play_message_sound" class="checkbox_label"> | ||||||
|  |                                     <input id="play_message_sound" type="checkbox" /> | ||||||
|  |                                     <audio id="audio_message_sound" src="sounds/message.mp3" hidden></audio> | ||||||
|  |                                     <span> | ||||||
|  |                                         <span data-i18n="Message Sound">Message Sound</span> | ||||||
|  |                                         <a href="https://docs.sillytavern.app/usage/guidebook/#message-sound" class="notes-link" target="_blank"> | ||||||
|  |                                             <span class="note-link-span">?</span> | ||||||
|  |                                         </a> | ||||||
|  |                                     </span> | ||||||
|  |                                 </label> | ||||||
|  |                                 <label for="play_sound_unfocused" class="checkbox_label"> | ||||||
|  |                                     <input id="play_sound_unfocused" type="checkbox" /> | ||||||
|  |                                     <span data-i18n="Background Sound Only">Background Sound Only</span> | ||||||
|  |                                 </label> | ||||||
|                                 <label for="fast_ui_mode" class="checkbox_label" title="removes blur and uses alternative background color for divs"> |                                 <label for="fast_ui_mode" class="checkbox_label" title="removes blur and uses alternative background color for divs"> | ||||||
|                                     <input id="fast_ui_mode" type="checkbox" /> |                                     <input id="fast_ui_mode" type="checkbox" /> | ||||||
|                                     <span data-i18n="No Blur Effect">No Blur Effect</span> |                                     <span data-i18n="No Blur Effect">No Blur Effect</span> | ||||||
| @@ -1900,6 +1914,11 @@ | |||||||
|                                     <span data-i18n="Message Timer">Message Timer</span> |                                     <span data-i18n="Message Timer">Message Timer</span> | ||||||
|                                 </label> |                                 </label> | ||||||
|  |  | ||||||
|  |                                 <label for="auto_scroll_chat_to_bottom" class="checkbox_label"> | ||||||
|  |                                     <input id="auto_scroll_chat_to_bottom" type="checkbox" /> | ||||||
|  |                                     <span data-i18n="Auto-scroll Chat">Auto-scroll Chat</span> | ||||||
|  |                                 </label> | ||||||
|  |  | ||||||
|                                 <label for="hotswapEnabled" class="checkbox_label"> |                                 <label for="hotswapEnabled" class="checkbox_label"> | ||||||
|                                     <input id="hotswapEnabled" type="checkbox" /> |                                     <input id="hotswapEnabled" type="checkbox" /> | ||||||
|                                     <span data-i18n="Characters Hotswap">Characters Hotswap</span> |                                     <span data-i18n="Characters Hotswap">Characters Hotswap</span> | ||||||
| @@ -2012,19 +2031,13 @@ | |||||||
|                                 <input id="swipes-checkbox" type="checkbox" /> |                                 <input id="swipes-checkbox" type="checkbox" /> | ||||||
|                                 <span data-i18n="Swipes">Swipes</span> |                                 <span data-i18n="Swipes">Swipes</span> | ||||||
|                             </label> |                             </label> | ||||||
|                             <label for="play_message_sound" class="checkbox_label"> |                             <label data-i18n="Prefer Character Card Prompt" for="prefer_character_prompt" title="If checked and the character card contains a prompt override (System Prompt), use that instead." class="checkbox_label"> | ||||||
|                                 <input id="play_message_sound" type="checkbox" /> |                                 <input id="prefer_character_prompt" type="checkbox" /> | ||||||
|                                 <audio id="audio_message_sound" src="sounds/message.mp3" hidden></audio> |                                 Prefer Char. Prompt | ||||||
|                                 <span> |  | ||||||
|                                     <span data-i18n="Message Sound">Message Sound</span> |  | ||||||
|                                     <a href="https://docs.sillytavern.app/usage/guidebook/#message-sound" class="notes-link" target="_blank"> |  | ||||||
|                                         <span class="note-link-span">?</span> |  | ||||||
|                                     </a> |  | ||||||
|                                 </span> |  | ||||||
|                             </label> |                             </label> | ||||||
|                             <label for="play_sound_unfocused" class="checkbox_label"> |                             <label data-i18n="Prefer Character Card Jailbreak" for="prefer_character_jailbreak" title="If checked and the character card contains a jailbreak override (Post History Instruction), use that instead." class="checkbox_label"> | ||||||
|                                 <input id="play_sound_unfocused" type="checkbox" /> |                                 <input id="prefer_character_jailbreak" type="checkbox" /> | ||||||
|                                 <span data-i18n="Background Sound Only">Background Sound Only</span> |                                 Prefer Char. JB | ||||||
|                             </label> |                             </label> | ||||||
|                             <label for="auto-load-chat-checkbox"><input id="auto-load-chat-checkbox" type="checkbox" /> |                             <label for="auto-load-chat-checkbox"><input id="auto-load-chat-checkbox" type="checkbox" /> | ||||||
|                                 <span data-i18n="Auto-load Last Chat">Auto-load Last Chat</span> |                                 <span data-i18n="Auto-load Last Chat">Auto-load Last Chat</span> | ||||||
| @@ -2038,15 +2051,11 @@ | |||||||
|                             </label> |                             </label> | ||||||
|                             <label class="checkbox_label" for="allow_name2_display"> |                             <label class="checkbox_label" for="allow_name2_display"> | ||||||
|                                 <input id="allow_name2_display" type="checkbox" /> |                                 <input id="allow_name2_display" type="checkbox" /> | ||||||
|                                 <span data-i18n="Allow {{char}}: in bot messages">Allow {{char}}: in bot messages</span> |                                 <span data-i18n="Allow {{char}}: in bot messages">Show {{char}} responses</span> | ||||||
|                             </label> |                             </label> | ||||||
|                             <label class="checkbox_label" for="allow_name1_display"> |                             <label class="checkbox_label" for="allow_name1_display"> | ||||||
|                                 <input id="allow_name1_display" type="checkbox" /> |                                 <input id="allow_name1_display" type="checkbox" /> | ||||||
|                                 <span data-i18n="Allow {{user}}: in bot messages">Allow {{user}}: in bot messages</span> |                                 <span data-i18n="Allow {{user}}: in bot messages">Show {{user}} responses</span> | ||||||
|                             </label> |  | ||||||
|                             <label for="auto_scroll_chat_to_bottom"> |  | ||||||
|                                 <input id="auto_scroll_chat_to_bottom" type="checkbox" /> |  | ||||||
|                                 <span data-i18n="Auto-scroll Chat">Auto-scroll Chat</span> |  | ||||||
|                             </label> |                             </label> | ||||||
|                             <label for="console_log_prompts"> |                             <label for="console_log_prompts"> | ||||||
|                                 <input id="console_log_prompts" type="checkbox" /> |                                 <input id="console_log_prompts" type="checkbox" /> | ||||||
|   | |||||||
| @@ -1898,6 +1898,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, | |||||||
|         let charPersonality = baseChatReplace(characters[this_chid].personality.trim(), name1, name2); |         let charPersonality = baseChatReplace(characters[this_chid].personality.trim(), name1, name2); | ||||||
|         let Scenario = baseChatReplace(scenarioText.trim(), name1, name2); |         let Scenario = baseChatReplace(scenarioText.trim(), name1, name2); | ||||||
|         let mesExamples = baseChatReplace(characters[this_chid].mes_example.trim(), name1, name2); |         let mesExamples = baseChatReplace(characters[this_chid].mes_example.trim(), name1, name2); | ||||||
|  |         let systemPrompt = baseChatReplace(characters[this_chid].data?.system_prompt?.trim(), name1, name2); | ||||||
|  |  | ||||||
|         // Parse example messages |         // Parse example messages | ||||||
|         if (!mesExamples.startsWith('<START>')) { |         if (!mesExamples.startsWith('<START>')) { | ||||||
| @@ -1956,7 +1957,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (isInstruct) { |         if (isInstruct) { | ||||||
|             storyString = formatInstructStoryString(storyString); |             storyString = formatInstructStoryString(storyString, systemPrompt); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         ////////////////////////////////// |         ////////////////////////////////// | ||||||
| @@ -2278,7 +2279,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, | |||||||
|                 generate_data = getNovelGenerationData(finalPromt, this_settings, this_amount_gen); |                 generate_data = getNovelGenerationData(finalPromt, this_settings, this_amount_gen); | ||||||
|             } |             } | ||||||
|             else if (main_api == 'openai') { |             else if (main_api == 'openai') { | ||||||
|                 let [prompt, counts] = await prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldInfoAfter, afterScenarioAnchor, promptBias, type, quiet_prompt); |                 let [prompt, counts] = await prepareOpenAIMessages(systemPrompt, name2, storyString, worldInfoBefore, worldInfoAfter, afterScenarioAnchor, promptBias, type, quiet_prompt); | ||||||
|                 generate_data = { prompt: prompt }; |                 generate_data = { prompt: prompt }; | ||||||
|  |  | ||||||
|                 // counts will return false if the user has not enabled the token breakdown feature |                 // counts will return false if the user has not enabled the token breakdown feature | ||||||
|   | |||||||
| @@ -310,7 +310,7 @@ function formatWorldInfo(value) { | |||||||
|     return stringFormat(oai_settings.wi_format, value); |     return stringFormat(oai_settings.wi_format, value); | ||||||
| } | } | ||||||
|  |  | ||||||
| async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldInfoAfter, extensionPrompt, bias, type, quietPrompt) { | async function prepareOpenAIMessages(systemPrompt, name2, storyString, worldInfoBefore, worldInfoAfter, extensionPrompt, bias, type, quietPrompt) { | ||||||
|     const isImpersonate = type == "impersonate"; |     const isImpersonate = type == "impersonate"; | ||||||
|     let this_max_context = oai_settings.openai_max_context; |     let this_max_context = oai_settings.openai_max_context; | ||||||
|     let enhance_definitions_prompt = ""; |     let enhance_definitions_prompt = ""; | ||||||
| @@ -324,7 +324,7 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI | |||||||
|     const wiBefore = formatWorldInfo(worldInfoBefore); |     const wiBefore = formatWorldInfo(worldInfoBefore); | ||||||
|     const wiAfter = formatWorldInfo(worldInfoAfter); |     const wiAfter = formatWorldInfo(worldInfoAfter); | ||||||
|  |  | ||||||
|     let whole_prompt = getSystemPrompt(nsfw_toggle_prompt, enhance_definitions_prompt, wiBefore, storyString, wiAfter, extensionPrompt, isImpersonate); |     let whole_prompt = getSystemPrompt(systemPrompt, nsfw_toggle_prompt, enhance_definitions_prompt, wiBefore, storyString, wiAfter, extensionPrompt, isImpersonate); | ||||||
|  |  | ||||||
|     // Join by a space and replace placeholders with real user/char names |     // Join by a space and replace placeholders with real user/char names | ||||||
|     storyString = substituteParams(whole_prompt.join("\n")).replace(/\r/gm, '').trim(); |     storyString = substituteParams(whole_prompt.join("\n")).replace(/\r/gm, '').trim(); | ||||||
| @@ -488,7 +488,9 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI | |||||||
|     ]; |     ]; | ||||||
| } | } | ||||||
|  |  | ||||||
| function getSystemPrompt(nsfw_toggle_prompt, enhance_definitions_prompt, wiBefore, storyString, wiAfter, extensionPrompt, isImpersonate) { | function getSystemPrompt(systemPrompt, nsfw_toggle_prompt, enhance_definitions_prompt, wiBefore, storyString, wiAfter, extensionPrompt, isImpersonate) { | ||||||
|  |     // If the character has a custom system prompt AND user has it preferred, use that instead of the default | ||||||
|  |     let prompt = power_user.prefer_character_prompt && systemPrompt ? systemPrompt : oai_settings.main_prompt; | ||||||
|     let whole_prompt = []; |     let whole_prompt = []; | ||||||
|  |  | ||||||
|     if (isImpersonate) { |     if (isImpersonate) { | ||||||
| @@ -497,10 +499,10 @@ function getSystemPrompt(nsfw_toggle_prompt, enhance_definitions_prompt, wiBefor | |||||||
|     else { |     else { | ||||||
|         // If it's toggled, NSFW prompt goes first. |         // If it's toggled, NSFW prompt goes first. | ||||||
|         if (oai_settings.nsfw_first) { |         if (oai_settings.nsfw_first) { | ||||||
|             whole_prompt = [nsfw_toggle_prompt, oai_settings.main_prompt, enhance_definitions_prompt + "\n\n" + wiBefore, storyString, wiAfter, extensionPrompt]; |             whole_prompt = [nsfw_toggle_prompt, prompt, enhance_definitions_prompt + "\n\n" + wiBefore, storyString, wiAfter, extensionPrompt]; | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             whole_prompt = [oai_settings.main_prompt, nsfw_toggle_prompt, enhance_definitions_prompt, "\n", wiBefore, storyString, wiAfter, extensionPrompt].filter(elem => elem); |             whole_prompt = [prompt, nsfw_toggle_prompt, enhance_definitions_prompt, "\n", wiBefore, storyString, wiAfter, extensionPrompt].filter(elem => elem); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return whole_prompt; |     return whole_prompt; | ||||||
|   | |||||||
| @@ -128,6 +128,8 @@ let power_user = { | |||||||
|     hotswap_enabled: true, |     hotswap_enabled: true, | ||||||
|     timer_enabled: true, |     timer_enabled: true, | ||||||
|     max_context_unlocked: false, |     max_context_unlocked: false, | ||||||
|  |     prefer_character_prompt: true, | ||||||
|  |     prefer_character_jailbreak: true, | ||||||
|  |  | ||||||
|     instruct: { |     instruct: { | ||||||
|         enabled: false, |         enabled: false, | ||||||
| @@ -527,6 +529,8 @@ function loadPowerUserSettings(settings, data) { | |||||||
|     $("#allow_name2_display").prop("checked", power_user.allow_name2_display); |     $("#allow_name2_display").prop("checked", power_user.allow_name2_display); | ||||||
|     $("#hotswapEnabled").prop("checked", power_user.hotswap_enabled); |     $("#hotswapEnabled").prop("checked", power_user.hotswap_enabled); | ||||||
|     $("#messageTimerEnabled").prop("checked", power_user.timer_enabled); |     $("#messageTimerEnabled").prop("checked", power_user.timer_enabled); | ||||||
|  |     $("#prefer_character_prompt").prop("checked", power_user.prefer_character_prompt); | ||||||
|  |     $("#prefer_character_jailbreak").prop("checked", power_user.prefer_character_jailbreak); | ||||||
|     $(`input[name="avatar_style"][value="${power_user.avatar_style}"]`).prop("checked", true); |     $(`input[name="avatar_style"][value="${power_user.avatar_style}"]`).prop("checked", true); | ||||||
|     $(`input[name="chat_display"][value="${power_user.chat_display}"]`).prop("checked", true); |     $(`input[name="chat_display"][value="${power_user.chat_display}"]`).prop("checked", true); | ||||||
|     $(`input[name="sheld_width"][value="${power_user.sheld_width}"]`).prop("checked", true); |     $(`input[name="sheld_width"][value="${power_user.sheld_width}"]`).prop("checked", true); | ||||||
| @@ -657,11 +661,13 @@ export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvata | |||||||
|     return text; |     return text; | ||||||
| } | } | ||||||
|  |  | ||||||
| export function formatInstructStoryString(story) { | export function formatInstructStoryString(story, systemPrompt) { | ||||||
|  |     // If the character has a custom system prompt AND user has it preferred, use that instead of the default | ||||||
|  |     systemPrompt = power_user.prefer_character_prompt && systemPrompt ? systemPrompt : power_user.instruct.system_prompt; | ||||||
|     const sequence = power_user.instruct.system_sequence || ''; |     const sequence = power_user.instruct.system_sequence || ''; | ||||||
|     const prompt = substituteParams(power_user.instruct.system_prompt) || ''; |     const prompt = substituteParams(systemPrompt) || ''; | ||||||
|     const separator = power_user.instruct.wrap ? '\n' : ''; |     const separator = power_user.instruct.wrap ? '\n' : ''; | ||||||
|     const textArray = [sequence, prompt, story, separator]; |     const textArray = [sequence, prompt + '\n' + story, separator]; | ||||||
|     const text = textArray.filter(x => x).join(separator); |     const text = textArray.filter(x => x).join(separator); | ||||||
|     return text; |     return text; | ||||||
| } | } | ||||||
| @@ -1170,6 +1176,18 @@ $(document).ready(() => { | |||||||
|         switchHotswap(); |         switchHotswap(); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  |     $("#prefer_character_prompt").on("input", function () { | ||||||
|  |         const value = !!$(this).prop('checked'); | ||||||
|  |         power_user.prefer_character_prompt = value; | ||||||
|  |         saveSettingsDebounced(); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     $("#prefer_character_jailbreak").on("input", function () { | ||||||
|  |         const value = !!$(this).prop('checked'); | ||||||
|  |         power_user.prefer_character_jailbreak = value; | ||||||
|  |         saveSettingsDebounced(); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|     $(window).on('focus', function () { |     $(window).on('focus', function () { | ||||||
|         browser_has_focus = true; |         browser_has_focus = true; | ||||||
|     }); |     }); | ||||||
|   | |||||||
| @@ -4576,4 +4576,4 @@ body.waifuMode #avatar_zoom_popup { | |||||||
|         overflow-y: auto; |         overflow-y: auto; | ||||||
|         overflow-x: hidden; |         overflow-x: hidden; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user