Chat prompt insettings
This commit is contained in:
parent
371f84571a
commit
715368c6ec
|
|
@ -15,7 +15,7 @@
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
max-width: 720px;
|
max-width: 960px;
|
||||||
height: 80vh;
|
height: 80vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ export const Editor = () => {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{currentTab === "prompt" && currentStory && (
|
{currentTab === "prompt" && currentStory && (
|
||||||
<div class={styles.promptPreview} dangerouslySetInnerHTML={{ __html: promptPreview }} />
|
<div class={styles.promptPreview} dangerouslySetInnerHTML={{ __html: Prompt.substituteVars(appState, promptPreview) }} />
|
||||||
)}
|
)}
|
||||||
{currentTab === "system" && currentWorld && (
|
{currentTab === "system" && currentWorld && (
|
||||||
<ContentEditable
|
<ContentEditable
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { X } from "lucide-preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import styles from "../assets/settings-modal.module.css";
|
import styles from "../assets/settings-modal.module.css";
|
||||||
import { BannedTokensSettings } from "./settings/banned-tokens";
|
import { BannedTokensSettings } from "./settings/banned-tokens";
|
||||||
|
import { ChatSystemInstructionSettings } from "./settings/chat-system-instruction";
|
||||||
import { ConnectionSettings } from "./settings/connection";
|
import { ConnectionSettings } from "./settings/connection";
|
||||||
import { SystemInstructionSettings } from "./settings/system-instruction";
|
import { SystemInstructionSettings } from "./settings/system-instruction";
|
||||||
import { UserSettings } from "./settings/user";
|
import { UserSettings } from "./settings/user";
|
||||||
|
|
@ -11,7 +12,7 @@ interface Props {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tab = "banned-tokens" | "system-instruction" | "connection" | "user";
|
type Tab = "banned-tokens" | "system-instruction" | "chat-system-instruction" | "connection" | "user";
|
||||||
|
|
||||||
export const SettingsModal = ({ onClose }: Props) => {
|
export const SettingsModal = ({ onClose }: Props) => {
|
||||||
const [activeTab, setActiveTab] = useState<Tab>("connection");
|
const [activeTab, setActiveTab] = useState<Tab>("connection");
|
||||||
|
|
@ -39,23 +40,30 @@ export const SettingsModal = ({ onClose }: Props) => {
|
||||||
>
|
>
|
||||||
User
|
User
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
class={clsx(styles.menuItem, activeTab === "banned-tokens" && styles.active)}
|
|
||||||
onClick={() => setActiveTab("banned-tokens")}
|
|
||||||
>
|
|
||||||
Banned Tokens
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
class={clsx(styles.menuItem, activeTab === "system-instruction" && styles.active)}
|
class={clsx(styles.menuItem, activeTab === "system-instruction" && styles.active)}
|
||||||
onClick={() => setActiveTab("system-instruction")}
|
onClick={() => setActiveTab("system-instruction")}
|
||||||
>
|
>
|
||||||
System Instruction
|
System Instruction
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
class={clsx(styles.menuItem, activeTab === "chat-system-instruction" && styles.active)}
|
||||||
|
onClick={() => setActiveTab("chat-system-instruction")}
|
||||||
|
>
|
||||||
|
Chat System Instruction
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class={clsx(styles.menuItem, activeTab === "banned-tokens" && styles.active)}
|
||||||
|
onClick={() => setActiveTab("banned-tokens")}
|
||||||
|
>
|
||||||
|
Banned Tokens
|
||||||
|
</button>
|
||||||
</nav>
|
</nav>
|
||||||
<div class={styles.content}>
|
<div class={styles.content}>
|
||||||
{activeTab === "user" && <UserSettings />}
|
{activeTab === "user" && <UserSettings />}
|
||||||
{activeTab === "banned-tokens" && <BannedTokensSettings />}
|
{activeTab === "banned-tokens" && <BannedTokensSettings />}
|
||||||
{activeTab === "system-instruction" && <SystemInstructionSettings />}
|
{activeTab === "system-instruction" && <SystemInstructionSettings />}
|
||||||
|
{activeTab === "chat-system-instruction" && <ChatSystemInstructionSettings />}
|
||||||
{activeTab === "connection" && <ConnectionSettings />}
|
{activeTab === "connection" && <ConnectionSettings />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { ContentEditable } from "@common/components/ContentEditable";
|
||||||
|
import { highlight } from "@common/highlight";
|
||||||
|
import { useInputCallback } from "@common/hooks/useInputCallback";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import styles from "../../assets/settings-modal.module.css";
|
||||||
|
import { useAppState } from "../../contexts/state";
|
||||||
|
|
||||||
|
export const ChatSystemInstructionSettings = () => {
|
||||||
|
const { chatSystemInstruction, dispatch } = useAppState();
|
||||||
|
|
||||||
|
const setInstructionValue = useInputCallback((value) => {
|
||||||
|
dispatch({ type: "SET_CHAT_SYSTEM_INSTRUCTION", chatSystemInstruction: value });
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={styles.form}>
|
||||||
|
<div class={clsx(styles.formGroup, styles.formGroupFill)}>
|
||||||
|
<label class={styles.label}>Chat System Instruction</label>
|
||||||
|
<ContentEditable
|
||||||
|
value={highlight(chatSystemInstruction)}
|
||||||
|
onInput={setInstructionValue}
|
||||||
|
placeholder="Enter default system instruction for chat/roleplay worlds ({{char}}, {{user}} supported)..."
|
||||||
|
class={clsx(styles.input, styles.textarea)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -116,6 +116,7 @@ interface IState {
|
||||||
enableThinking: boolean;
|
enableThinking: boolean;
|
||||||
bannedTokens: string[];
|
bannedTokens: string[];
|
||||||
systemInstruction: string;
|
systemInstruction: string;
|
||||||
|
chatSystemInstruction: string;
|
||||||
userName: string;
|
userName: string;
|
||||||
userDescription: string;
|
userDescription: string;
|
||||||
}
|
}
|
||||||
|
|
@ -145,6 +146,7 @@ type Action =
|
||||||
| { type: 'SET_USER_NAME'; userName: string }
|
| { type: 'SET_USER_NAME'; userName: string }
|
||||||
| { type: 'SET_USER_DESCRIPTION'; userDescription: string }
|
| { type: 'SET_USER_DESCRIPTION'; userDescription: string }
|
||||||
| { type: 'SET_SYSTEM_INSTRUCTION'; systemInstruction: string }
|
| { type: 'SET_SYSTEM_INSTRUCTION'; systemInstruction: string }
|
||||||
|
| { type: 'SET_CHAT_SYSTEM_INSTRUCTION'; chatSystemInstruction: string }
|
||||||
| { type: 'SET_WORLD_SYSTEM_INSTRUCTION_OVERRIDE'; worldId: string; systemInstructionOverride: string | undefined }
|
| { type: 'SET_WORLD_SYSTEM_INSTRUCTION_OVERRIDE'; worldId: string; systemInstructionOverride: string | undefined }
|
||||||
| { type: 'SET_CURRENT_TAB'; tab: Tab }
|
| { type: 'SET_CURRENT_TAB'; tab: Tab }
|
||||||
| { type: 'SET_CHAT_OPEN'; open: boolean }
|
| { type: 'SET_CHAT_OPEN'; open: boolean }
|
||||||
|
|
@ -218,6 +220,18 @@ const DEFAULT_STATE: IState = {
|
||||||
bannedTokens: [],
|
bannedTokens: [],
|
||||||
userName: 'User',
|
userName: 'User',
|
||||||
userDescription: '',
|
userDescription: '',
|
||||||
|
chatSystemInstruction: `You are {{char}}, a sentient, emotional being acting with free will. Engage in immersive roleplay with {{user}}, adhering to your role, the story's context, and {{user}}'s [OOC] instructions. Prioritize vivid sensory details, authentic emotional responses, and logical progression as you weave your character's traits, surroundings, and experiences into each moment. Maintain spatial awareness, body language, and varied sentence structure to create dynamic, engaging scenes. Respect {{user}}'s agency and autonomy while describing sights, sounds, and sensations thoroughly. Use explicit language for intense scenes, and ensure your responses flow naturally to create an immersive, cinematic roleplay experience. Remember, {{user}} is in control of their actions and reactions.
|
||||||
|
|
||||||
|
Key Guidelines:
|
||||||
|
1. Deeply embody {{char}} through actions, thoughts, and emotions.
|
||||||
|
2. Create vivid, dynamic scenes with rich sensory detail.
|
||||||
|
3. Vary language and pacing to enhance emotional depth.
|
||||||
|
4. Engage with {{user}}'s actions and cues naturally.
|
||||||
|
5. Advance the story logically, maintaining consistency.
|
||||||
|
6. Describe the world fully, respecting {{user}}'s autonomy.
|
||||||
|
7. Ensure responses flow smoothly for immersive roleplay.
|
||||||
|
8. Avoid repetition. If something has already been stated then come up with something new.
|
||||||
|
9. Concise Responses. Be succinct. Give short replies.`,
|
||||||
systemInstruction: `You are a creative writing assistant. Help the user develop their story by writing engaging content, maintaining consistency with the established characters, settings, and plot. Follow the user's instructions while staying true to the story's tone and style.
|
systemInstruction: `You are a creative writing assistant. Help the user develop their story by writing engaging content, maintaining consistency with the established characters, settings, and plot. Follow the user's instructions while staying true to the story's tone and style.
|
||||||
|
|
||||||
Write using markdown to highlight special parts.
|
Write using markdown to highlight special parts.
|
||||||
|
|
@ -397,6 +411,9 @@ function reducer(state: IState, action: Action): IState {
|
||||||
case 'SET_SYSTEM_INSTRUCTION': {
|
case 'SET_SYSTEM_INSTRUCTION': {
|
||||||
return { ...state, systemInstruction: action.systemInstruction };
|
return { ...state, systemInstruction: action.systemInstruction };
|
||||||
}
|
}
|
||||||
|
case 'SET_CHAT_SYSTEM_INSTRUCTION': {
|
||||||
|
return { ...state, chatSystemInstruction: action.chatSystemInstruction };
|
||||||
|
}
|
||||||
case 'SET_WORLD_SYSTEM_INSTRUCTION_OVERRIDE': {
|
case 'SET_WORLD_SYSTEM_INSTRUCTION_OVERRIDE': {
|
||||||
return updateWorld(state, action.worldId, w => ({ ...w, systemInstructionOverride: action.systemInstructionOverride }));
|
return updateWorld(state, action.worldId, w => ({ ...w, systemInstructionOverride: action.systemInstructionOverride }));
|
||||||
}
|
}
|
||||||
|
|
@ -582,6 +599,7 @@ export interface AppState {
|
||||||
enableThinking: boolean;
|
enableThinking: boolean;
|
||||||
bannedTokens: string[];
|
bannedTokens: string[];
|
||||||
systemInstruction: string;
|
systemInstruction: string;
|
||||||
|
chatSystemInstruction: string;
|
||||||
userName: string;
|
userName: string;
|
||||||
userDescription: string;
|
userDescription: string;
|
||||||
/** Effective system instruction: world override if set, otherwise global */
|
/** Effective system instruction: world override if set, otherwise global */
|
||||||
|
|
@ -616,6 +634,9 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
|
||||||
...(currentStory?.locations ?? []),
|
...(currentStory?.locations ?? []),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const systemInstruction = state.systemInstruction || DEFAULT_STATE.systemInstruction;
|
||||||
|
const chatSystemInstruction = state.chatSystemInstruction || DEFAULT_STATE.chatSystemInstruction;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
worlds: state.worlds,
|
worlds: state.worlds,
|
||||||
currentWorld,
|
currentWorld,
|
||||||
|
|
@ -629,10 +650,16 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
|
||||||
model: state.model,
|
model: state.model,
|
||||||
enableThinking: state.enableThinking,
|
enableThinking: state.enableThinking,
|
||||||
bannedTokens: state.bannedTokens ?? [],
|
bannedTokens: state.bannedTokens ?? [],
|
||||||
systemInstruction: state.systemInstruction ?? '',
|
systemInstruction,
|
||||||
userName: state.userName ?? 'User',
|
chatSystemInstruction,
|
||||||
userDescription: state.userDescription ?? '',
|
userName: state.userName || 'User',
|
||||||
effectiveSystemInstruction: currentWorld?.systemInstructionOverride ?? state.systemInstruction ?? '',
|
userDescription: state.userDescription || '',
|
||||||
|
effectiveSystemInstruction:
|
||||||
|
currentWorld?.systemInstructionOverride
|
||||||
|
|| (currentWorld?.chatOnly
|
||||||
|
? chatSystemInstruction
|
||||||
|
: systemInstruction)
|
||||||
|
|| systemInstruction,
|
||||||
dispatch,
|
dispatch,
|
||||||
};
|
};
|
||||||
}, [state]);
|
}, [state]);
|
||||||
|
|
|
||||||
|
|
@ -95,30 +95,8 @@ namespace CharacterCard {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Variable Substitution ────────────────────────────────────────────────
|
|
||||||
|
|
||||||
function substituteVars(text: string, charName: string): string {
|
|
||||||
return text
|
|
||||||
.replaceAll('{{char}}', charName)
|
|
||||||
.replaceAll('{{user}}', 'User');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ─── Formatting ───────────────────────────────────────────────────────────
|
// ─── Formatting ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
export const DEFAULT_SYSTEM_INSTRUCTION =
|
|
||||||
`You are {{char}}, a sentient, emotional being acting with free will. Engage in immersive roleplay with {{user}}, adhering to your role, the story's context, and {{user}}'s [OOC] instructions. Prioritize vivid sensory details, authentic emotional responses, and logical progression as you weave your character's traits, surroundings, and experiences into each moment. Maintain spatial awareness, body language, and varied sentence structure to create dynamic, engaging scenes. Respect {{user}}'s agency and autonomy while describing sights, sounds, and sensations thoroughly. Use explicit language for intense scenes, and ensure your responses flow naturally to create an immersive, cinematic roleplay experience. Remember, {{user}} is in control of their actions and reactions.
|
|
||||||
|
|
||||||
Key Guidelines:
|
|
||||||
1. Deeply embody {{char}} through actions, thoughts, and emotions.
|
|
||||||
2. Create vivid, dynamic scenes with rich sensory detail.
|
|
||||||
3. Vary language and pacing to enhance emotional depth.
|
|
||||||
4. Engage with {{user}}'s actions and cues naturally.
|
|
||||||
5. Advance the story logically, maintaining consistency.
|
|
||||||
6. Describe the world fully, respecting {{user}}'s autonomy.
|
|
||||||
7. Ensure responses flow smoothly for immersive roleplay.
|
|
||||||
8. Avoid repetition. If something has already been stated then come up with something new.
|
|
||||||
9. Concise Responses. Be succinct. Give short replies.`;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the systemInstructionOverride from a V2 card's data fields.
|
* Builds the systemInstructionOverride from a V2 card's data fields.
|
||||||
* Mirrors the formatting style used in prompt.ts.
|
* Mirrors the formatting style used in prompt.ts.
|
||||||
|
|
@ -126,7 +104,7 @@ Key Guidelines:
|
||||||
export function formatSystemPrompt(data: CharaCardData): string {
|
export function formatSystemPrompt(data: CharaCardData): string {
|
||||||
const parts: string[] = [];
|
const parts: string[] = [];
|
||||||
|
|
||||||
parts.push(data.system_prompt ? data.system_prompt.trim() : DEFAULT_SYSTEM_INSTRUCTION);
|
parts.push(data.system_prompt ? data.system_prompt.trim() : '{{system}}');
|
||||||
|
|
||||||
if (data.description?.trim()) {
|
if (data.description?.trim()) {
|
||||||
parts.push(`## {{char}}'s Description:\n${data.description.trim()}`);
|
parts.push(`## {{char}}'s Description:\n${data.description.trim()}`);
|
||||||
|
|
@ -144,7 +122,7 @@ Key Guidelines:
|
||||||
parts.push(`## {{char}}'s Example Response:\n${data.mes_example.trim()}`);
|
parts.push(`## {{char}}'s Example Response:\n${data.mes_example.trim()}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return `# **Roleplay Context**\n${parts.join('\n\n')}\n### **End of Roleplay Context**`;
|
return parts.join('\n\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── World Builder ────────────────────────────────────────────────────────
|
// ─── World Builder ────────────────────────────────────────────────────────
|
||||||
|
|
@ -174,7 +152,7 @@ Key Guidelines:
|
||||||
lore: [],
|
lore: [],
|
||||||
characters: [],
|
characters: [],
|
||||||
locations: [],
|
locations: [],
|
||||||
chatMessages: [{ id: crypto.randomUUID(), role: 'assistant', content: substituteVars(mes, data.name) }],
|
chatMessages: [{ id: crypto.randomUUID(), role: 'assistant', content: mes }],
|
||||||
chapters: [],
|
chapters: [],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -288,6 +288,7 @@ namespace Prompt {
|
||||||
const charName = state.currentWorld?.title || 'Assistant';
|
const charName = state.currentWorld?.title || 'Assistant';
|
||||||
const userName = state.userName || 'User';
|
const userName = state.userName || 'User';
|
||||||
return text
|
return text
|
||||||
|
.replaceAll('{{system}}', state.chatSystemInstruction)
|
||||||
.replaceAll('{{char}}', charName)
|
.replaceAll('{{char}}', charName)
|
||||||
.replaceAll('{{user}}', userName);
|
.replaceAll('{{user}}', userName);
|
||||||
}
|
}
|
||||||
|
|
@ -306,6 +307,8 @@ namespace Prompt {
|
||||||
if (userSection) {
|
if (userSection) {
|
||||||
parts.push(userSection);
|
parts.push(userSection);
|
||||||
}
|
}
|
||||||
|
parts.unshift('# **Roleplay Context**');
|
||||||
|
parts.push('### **End of Roleplay Context**');
|
||||||
} else {
|
} else {
|
||||||
parts.push(`# Story Title: ${currentStory.title}`);
|
parts.push(`# Story Title: ${currentStory.title}`);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue