Compare commits
2 Commits
b95506a095
...
b8090dac86
| Author | SHA1 | Date |
|---|---|---|
|
|
b8090dac86 | |
|
|
cc43e035fe |
|
|
@ -13,12 +13,13 @@ import { Ace } from "../ace";
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
const { modelName, modelTemplate, contextLength, promptTokens, blockConnection } = useContext(LLMContext);
|
const { modelName, modelTemplate, contextLength, promptTokens, blockConnection } = useContext(LLMContext);
|
||||||
const {
|
const {
|
||||||
messages, connectionUrl, systemPrompt, lore, userPrompt, bannedWords, instruct,
|
messages, connectionUrl, systemPrompt, lore, userPrompt, bannedWords, instruct, summarizePrompt,
|
||||||
setConnectionUrl, setSystemPrompt, setLore, setUserPrompt, addSwipe, setBannedWords, setInstruct
|
setConnectionUrl, setSystemPrompt, setLore, setUserPrompt, addSwipe, setBannedWords, setInstruct, setSummarizePrompt,
|
||||||
} = useContext(StateContext);
|
} = useContext(StateContext);
|
||||||
|
|
||||||
const loreOpen = useBool();
|
const loreOpen = useBool();
|
||||||
const promptsOpen = useBool();
|
const promptsOpen = useBool();
|
||||||
|
const genparamsOpen = useBool();
|
||||||
const assistantOpen = useBool();
|
const assistantOpen = useBool();
|
||||||
|
|
||||||
const bannedWordsInput = useMemo(() => bannedWords.join('\n'), [bannedWords]);
|
const bannedWordsInput = useMemo(() => bannedWords.join('\n'), [bannedWords]);
|
||||||
|
|
@ -46,7 +47,7 @@ export const Header = () => {
|
||||||
|
|
||||||
const handleBlurBannedWords = useCallback((e: Event) => {
|
const handleBlurBannedWords = useCallback((e: Event) => {
|
||||||
if (e.target instanceof HTMLTextAreaElement) {
|
if (e.target instanceof HTMLTextAreaElement) {
|
||||||
const words = e.target.value.split('\n').sort();
|
const words = e.target.value.toLowerCase().split('\n').sort();
|
||||||
setBannedWords(words);
|
setBannedWords(words);
|
||||||
}
|
}
|
||||||
}, [setBannedWords]);
|
}, [setBannedWords]);
|
||||||
|
|
@ -83,6 +84,9 @@ export const Header = () => {
|
||||||
<button class='icon color' title='Edit lore' onClick={loreOpen.setTrue}>
|
<button class='icon color' title='Edit lore' onClick={loreOpen.setTrue}>
|
||||||
🌍
|
🌍
|
||||||
</button>
|
</button>
|
||||||
|
<button class='icon color' title='Generation parameters' onClick={genparamsOpen.setTrue}>
|
||||||
|
⚙
|
||||||
|
</button>
|
||||||
<button class='icon color' title='Edit prompts' onClick={promptsOpen.setTrue}>
|
<button class='icon color' title='Edit prompts' onClick={promptsOpen.setTrue}>
|
||||||
📃
|
📃
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -100,6 +104,19 @@ export const Header = () => {
|
||||||
placeholder="Describe your world, for example: World of Awoo has big mountains and wide rivers."
|
placeholder="Describe your world, for example: World of Awoo has big mountains and wide rivers."
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<Modal open={genparamsOpen.value} onClose={genparamsOpen.setFalse}>
|
||||||
|
<h3 class={styles.modalTitle}>Generation Parameters</h3>
|
||||||
|
<div className={styles.scrollPane}>
|
||||||
|
<h4 class={styles.modalTitle}>Banned phrases</h4>
|
||||||
|
<AutoTextarea
|
||||||
|
placeholder="Each phrase on separate line"
|
||||||
|
value={bannedWordsInput}
|
||||||
|
onInput={handleSetBannedWords}
|
||||||
|
onBlur={handleBlurBannedWords}
|
||||||
|
class={styles.template}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
<Modal open={promptsOpen.value} onClose={promptsOpen.setFalse}>
|
<Modal open={promptsOpen.value} onClose={promptsOpen.setFalse}>
|
||||||
<h3 class={styles.modalTitle}>Prompts Editor</h3>
|
<h3 class={styles.modalTitle}>Prompts Editor</h3>
|
||||||
<div className={styles.scrollPane}>
|
<div className={styles.scrollPane}>
|
||||||
|
|
@ -109,17 +126,11 @@ export const Header = () => {
|
||||||
<h4 class={styles.modalTitle}>User prompt template</h4>
|
<h4 class={styles.modalTitle}>User prompt template</h4>
|
||||||
<Ace value={userPrompt} onInput={setUserPrompt} />
|
<Ace value={userPrompt} onInput={setUserPrompt} />
|
||||||
<hr />
|
<hr />
|
||||||
|
<h4 class={styles.modalTitle}>Summary template</h4>
|
||||||
|
<Ace value={summarizePrompt} onInput={setSummarizePrompt} />
|
||||||
|
<hr />
|
||||||
<h4 class={styles.modalTitle}>Instruct template</h4>
|
<h4 class={styles.modalTitle}>Instruct template</h4>
|
||||||
<Ace value={instruct} onInput={setInstruct} />
|
<Ace value={instruct} onInput={setInstruct} />
|
||||||
<hr />
|
|
||||||
<h4 class={styles.modalTitle}>Banned phrases</h4>
|
|
||||||
<AutoTextarea
|
|
||||||
placeholder="Each phrase on separate line"
|
|
||||||
value={bannedWordsInput}
|
|
||||||
onInput={handleSetBannedWords}
|
|
||||||
onBlur={handleBlurBannedWords}
|
|
||||||
class={styles.template}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
<MiniChat
|
<MiniChat
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,14 @@
|
||||||
border: var(--border);
|
border: var(--border);
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
height: unset;
|
height: unset;
|
||||||
resize: vertical;
|
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary {
|
||||||
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttons {
|
.buttons {
|
||||||
|
|
|
||||||
|
|
@ -14,25 +14,31 @@ interface IProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Message = ({ message, index, isLastUser, isLastAssistant }: IProps) => {
|
export const Message = ({ message, index, isLastUser, isLastAssistant }: IProps) => {
|
||||||
const { editMessage, deleteMessage, setCurrentSwipe, addSwipe } = useContext(StateContext);
|
const { messages, editMessage, editSummary, deleteMessage, setCurrentSwipe, setMessages } = useContext(StateContext);
|
||||||
const [editing, setEditing] = useState(false);
|
const [editing, setEditing] = useState(false);
|
||||||
const [savedMessage, setSavedMessage] = useState('');
|
const [editedMessage, setEditedMessage] = useState('');
|
||||||
const textRef = useRef<HTMLDivElement>(null);
|
const textRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const content = useMemo(() => MessageTools.getSwipe(message)?.content, [message]);
|
const swipe = useMemo(() => MessageTools.getSwipe(message), [message]);
|
||||||
|
|
||||||
|
const content = swipe?.content;
|
||||||
|
const summary = swipe?.summary;
|
||||||
const htmlContent = useMemo(() => MessageTools.format(content ?? ''), [content]);
|
const htmlContent = useMemo(() => MessageTools.format(content ?? ''), [content]);
|
||||||
|
|
||||||
const handleToggleEdit = useCallback(() => {
|
const handleEnableEdit = useCallback(() => {
|
||||||
setEditing(!editing);
|
setEditing(true);
|
||||||
if (!editing) {
|
setEditedMessage(content ?? '');
|
||||||
setSavedMessage(content ?? '');
|
}, [content]);
|
||||||
}
|
|
||||||
}, [editing, content]);
|
const handleSaveEdit = useCallback(() => {
|
||||||
|
editMessage(index, editedMessage.trim());
|
||||||
|
editSummary(index, '');
|
||||||
|
setEditing(false);
|
||||||
|
}, [editMessage, editSummary, index, editedMessage]);
|
||||||
|
|
||||||
const handleCancelEdit = useCallback(() => {
|
const handleCancelEdit = useCallback(() => {
|
||||||
setEditing(false);
|
setEditing(false);
|
||||||
editMessage(index, savedMessage);
|
}, [editMessage, index]);
|
||||||
}, [editMessage, index, savedMessage]);
|
|
||||||
|
|
||||||
const handleDeleteMessage = useCallback(() => {
|
const handleDeleteMessage = useCallback(() => {
|
||||||
if (confirm('Delete message?')) {
|
if (confirm('Delete message?')) {
|
||||||
|
|
@ -41,12 +47,19 @@ export const Message = ({ message, index, isLastUser, isLastAssistant }: IProps)
|
||||||
}
|
}
|
||||||
}, [deleteMessage, index]);
|
}, [deleteMessage, index]);
|
||||||
|
|
||||||
|
const handleStopHere = useCallback(() => {
|
||||||
|
if (confirm('Delete all messages after that?')) {
|
||||||
|
setMessages(messages.filter((_, i) => i <= index));
|
||||||
|
setEditing(false);
|
||||||
|
}
|
||||||
|
}, [messages, setMessages, index]);
|
||||||
|
|
||||||
const handleEdit = useCallback((e: InputEvent) => {
|
const handleEdit = useCallback((e: InputEvent) => {
|
||||||
if (e.target instanceof HTMLTextAreaElement) {
|
if (e.target instanceof HTMLTextAreaElement) {
|
||||||
const newContent = e.target.value;
|
const newContent = e.target.value;
|
||||||
editMessage(index, newContent);
|
setEditedMessage(newContent);
|
||||||
}
|
}
|
||||||
}, [editMessage, index]);
|
}, []);
|
||||||
|
|
||||||
const handleSwipeLeft = useCallback(() => {
|
const handleSwipeLeft = useCallback(() => {
|
||||||
setCurrentSwipe(index, message.currentSwipe - 1);
|
setCurrentSwipe(index, message.currentSwipe - 1);
|
||||||
|
|
@ -62,16 +75,20 @@ export const Message = ({ message, index, isLastUser, isLastAssistant }: IProps)
|
||||||
<div class={`${styles.message} ${styles[message.role]} ${isLastUser ? styles.lastUser : ''}`}>
|
<div class={`${styles.message} ${styles[message.role]} ${isLastUser ? styles.lastUser : ''}`}>
|
||||||
<div class={styles.content}>
|
<div class={styles.content}>
|
||||||
{editing
|
{editing
|
||||||
? <AutoTextarea onInput={handleEdit} value={content} />
|
? <AutoTextarea onInput={handleEdit} value={editedMessage} />
|
||||||
: <div class={styles.text} dangerouslySetInnerHTML={{ __html: htmlContent }} ref={textRef} />
|
: <>
|
||||||
|
<div class={styles.text} dangerouslySetInnerHTML={{ __html: htmlContent }} ref={textRef} />
|
||||||
|
{summary && <small class={styles.summary}>{summary}</small>}
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
{(isLastUser || message.role === 'assistant') &&
|
{(isLastUser || message.role === 'assistant') &&
|
||||||
<div class={styles.buttons}>
|
<div class={styles.buttons}>
|
||||||
{editing
|
{editing
|
||||||
? <>
|
? <>
|
||||||
<button class='icon' onClick={handleToggleEdit}>✔</button>
|
<button class='icon' onClick={handleSaveEdit} title='Save'>✔</button>
|
||||||
<button class='icon' onClick={handleDeleteMessage}>🗑️</button>
|
<button class='icon' onClick={handleDeleteMessage} title='Delete'>🗑️</button>
|
||||||
<button class='icon' onClick={handleCancelEdit}>❌</button>
|
<button class='icon' onClick={handleStopHere} title='Stop here'>⛔</button>
|
||||||
|
<button class='icon' onClick={handleCancelEdit} title='Cancel'>❌</button>
|
||||||
</>
|
</>
|
||||||
: <>
|
: <>
|
||||||
{isLastAssistant &&
|
{isLastAssistant &&
|
||||||
|
|
@ -81,7 +98,7 @@ export const Message = ({ message, index, isLastUser, isLastAssistant }: IProps)
|
||||||
<div onClick={handleSwipeRight}>▶</div>
|
<div onClick={handleSwipeRight}>▶</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<button class='icon' onClick={handleToggleEdit} title="Edit">🖊</button>
|
<button class='icon' onClick={handleEnableEdit} title="Edit">🖊</button>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -58,11 +58,11 @@ export const MiniChat = ({ history = [], buttons = {}, open, onClose }: IProps)
|
||||||
|
|
||||||
for await (const chunk of generate(prompt)) {
|
for await (const chunk of generate(prompt)) {
|
||||||
text += chunk;
|
text += chunk;
|
||||||
setMessages(MessageTools.updateContent(newMessages, messageId, text));
|
setMessages(MessageTools.updateSwipe(newMessages, messageId, text));
|
||||||
}
|
}
|
||||||
|
|
||||||
setMessages([
|
setMessages([
|
||||||
...MessageTools.updateContent(newMessages, messageId, MessageTools.trimSentence(text)),
|
...MessageTools.updateSwipe(newMessages, messageId, MessageTools.trimSentence(text)),
|
||||||
MessageTools.create('', 'user', true),
|
MessageTools.create('', 'user', true),
|
||||||
]);
|
]);
|
||||||
MessageTools.playReady();
|
MessageTools.playReady();
|
||||||
|
|
@ -78,7 +78,7 @@ export const MiniChat = ({ history = [], buttons = {}, open, onClose }: IProps)
|
||||||
|
|
||||||
const handleChange = useCallback((i: number, e: InputEvent) => {
|
const handleChange = useCallback((i: number, e: InputEvent) => {
|
||||||
if (e.target instanceof HTMLTextAreaElement) {
|
if (e.target instanceof HTMLTextAreaElement) {
|
||||||
setMessages(MessageTools.updateContent(messages, i, e.target.value));
|
setMessages(MessageTools.updateSwipe(messages, i, e.target.value));
|
||||||
}
|
}
|
||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import { Huggingface } from "../huggingface";
|
||||||
|
|
||||||
interface ICompileArgs {
|
interface ICompileArgs {
|
||||||
keepUsers?: number;
|
keepUsers?: number;
|
||||||
|
raw?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ICompiledPrompt {
|
interface ICompiledPrompt {
|
||||||
|
|
@ -47,6 +48,7 @@ type IGenerationSettings = Partial<typeof DEFAULT_GENERATION_SETTINGS>;
|
||||||
interface IActions {
|
interface IActions {
|
||||||
compilePrompt: (messages: IMessage[], args?: ICompileArgs) => Promise<ICompiledPrompt>;
|
compilePrompt: (messages: IMessage[], args?: ICompileArgs) => Promise<ICompiledPrompt>;
|
||||||
generate: (prompt: string, extraSettings?: IGenerationSettings) => AsyncGenerator<string>;
|
generate: (prompt: string, extraSettings?: IGenerationSettings) => AsyncGenerator<string>;
|
||||||
|
summarize: (content: string) => Promise<string>;
|
||||||
countTokens: (prompt: string) => Promise<number>;
|
countTokens: (prompt: string) => Promise<number>;
|
||||||
}
|
}
|
||||||
export type ILLMContext = IContext & IActions;
|
export type ILLMContext = IContext & IActions;
|
||||||
|
|
@ -81,11 +83,12 @@ export const LLMContext = createContext<ILLMContext>({} as ILLMContext);
|
||||||
|
|
||||||
export const LLMContextProvider = ({ children }: { children?: any }) => {
|
export const LLMContextProvider = ({ children }: { children?: any }) => {
|
||||||
const {
|
const {
|
||||||
connectionUrl, messages, triggerNext, lore, userPrompt, systemPrompt, bannedWords, instruct,
|
connectionUrl, messages, triggerNext, lore, userPrompt, systemPrompt, bannedWords, instruct, summarizePrompt,
|
||||||
setTriggerNext, addMessage, editMessage, setInstruct,
|
setTriggerNext, addMessage, editMessage, editSummary, setInstruct,
|
||||||
} = useContext(StateContext);
|
} = useContext(StateContext);
|
||||||
|
|
||||||
const generating = useBool(false);
|
const generating = useBool(false);
|
||||||
|
const summarizing = useBool(false);
|
||||||
const blockConnection = useBool(false);
|
const blockConnection = useBool(false);
|
||||||
const [promptTokens, setPromptTokens] = useState(0);
|
const [promptTokens, setPromptTokens] = useState(0);
|
||||||
const [contextLength, setContextLength] = useState(0);
|
const [contextLength, setContextLength] = useState(0);
|
||||||
|
|
@ -285,6 +288,14 @@ export const LLMContextProvider = ({ children }: { children?: any }) => {
|
||||||
generating.setFalse();
|
generating.setFalse();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
summarize: async (message) => {
|
||||||
|
const content = Huggingface.applyTemplate(summarizePrompt, { message });
|
||||||
|
const prompt = Huggingface.applyChatTemplate(instruct, [{ role: 'user', content }]);
|
||||||
|
|
||||||
|
const tokens = await Array.fromAsync(actions.generate(prompt));
|
||||||
|
|
||||||
|
return MessageTools.trimSentence(tokens.join(''));
|
||||||
|
},
|
||||||
countTokens: async (prompt) => {
|
countTokens: async (prompt) => {
|
||||||
if (!connectionUrl) {
|
if (!connectionUrl) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -305,7 +316,7 @@ export const LLMContextProvider = ({ children }: { children?: any }) => {
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
}), [connectionUrl, lore, userPromptTemplate, systemPrompt, bannedWords, instruct]);
|
}), [connectionUrl, lore, userPromptTemplate, systemPrompt, bannedWords, instruct, summarizePrompt]);
|
||||||
|
|
||||||
useEffect(() => void (async () => {
|
useEffect(() => void (async () => {
|
||||||
if (triggerNext && !generating.value) {
|
if (triggerNext && !generating.value) {
|
||||||
|
|
@ -323,14 +334,16 @@ export const LLMContextProvider = ({ children }: { children?: any }) => {
|
||||||
messageId++;
|
messageId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editSummary(messageId, 'Generating...');
|
||||||
for await (const chunk of actions.generate(prompt)) {
|
for await (const chunk of actions.generate(prompt)) {
|
||||||
text += chunk;
|
text += chunk;
|
||||||
setPromptTokens(tokens + Math.round(text.length * 0.25));
|
setPromptTokens(tokens + Math.round(text.length * 0.25));
|
||||||
editMessage(messageId, text);
|
editMessage(messageId, text.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
text = MessageTools.trimSentence(text);
|
text = MessageTools.trimSentence(text);
|
||||||
editMessage(messageId, text);
|
editMessage(messageId, text);
|
||||||
|
editSummary(messageId, '');
|
||||||
|
|
||||||
setPromptTokens(0); // trigger calculation
|
setPromptTokens(0); // trigger calculation
|
||||||
|
|
||||||
|
|
@ -338,6 +351,21 @@ export const LLMContextProvider = ({ children }: { children?: any }) => {
|
||||||
}
|
}
|
||||||
})(), [actions, triggerNext, messages, generating.value]);
|
})(), [actions, triggerNext, messages, generating.value]);
|
||||||
|
|
||||||
|
useEffect(() => void (async () => {
|
||||||
|
if (!generating.value && !summarizing.value) {
|
||||||
|
summarizing.setTrue();
|
||||||
|
for (let id = 0; id < messages.length; id++) {
|
||||||
|
const message = messages[id];
|
||||||
|
const swipe = MessageTools.getSwipe(message);
|
||||||
|
if (message.role === 'assistant' && swipe?.content?.includes('\n') && !swipe.summary) {
|
||||||
|
const summary = await actions.summarize(swipe.content);
|
||||||
|
editSummary(id, summary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
summarizing.setFalse();
|
||||||
|
}
|
||||||
|
})(), [messages, generating.value, summarizing.value]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!blockConnection.value) {
|
if (!blockConnection.value) {
|
||||||
setPromptTokens(0);
|
setPromptTokens(0);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ interface IContext {
|
||||||
systemPrompt: string;
|
systemPrompt: string;
|
||||||
lore: string;
|
lore: string;
|
||||||
userPrompt: string;
|
userPrompt: string;
|
||||||
|
summarizePrompt: string;
|
||||||
bannedWords: string[];
|
bannedWords: string[];
|
||||||
messages: IMessage[];
|
messages: IMessage[];
|
||||||
triggerNext: boolean;
|
triggerNext: boolean;
|
||||||
|
|
@ -22,12 +23,14 @@ interface IActions {
|
||||||
setLore: (lore: string | Event) => void;
|
setLore: (lore: string | Event) => void;
|
||||||
setSystemPrompt: (prompt: string | Event) => void;
|
setSystemPrompt: (prompt: string | Event) => void;
|
||||||
setUserPrompt: (prompt: string | Event) => void;
|
setUserPrompt: (prompt: string | Event) => void;
|
||||||
|
setSummarizePrompt: (prompt: string | Event) => void;
|
||||||
setBannedWords: (words: string[]) => void;
|
setBannedWords: (words: string[]) => void;
|
||||||
setTriggerNext: (triggerNext: boolean) => void;
|
setTriggerNext: (triggerNext: boolean) => void;
|
||||||
|
|
||||||
setMessages: (messages: IMessage[]) => void;
|
setMessages: (messages: IMessage[]) => void;
|
||||||
addMessage: (content: string, role: IMessage['role'], triggerNext?: boolean) => void;
|
addMessage: (content: string, role: IMessage['role'], triggerNext?: boolean) => void;
|
||||||
editMessage: (index: number, content: string, triggerNext?: boolean) => void;
|
editMessage: (index: number, content: string) => void;
|
||||||
|
editSummary: (index: number, summary: string) => void;
|
||||||
deleteMessage: (index: number) => void;
|
deleteMessage: (index: number) => void;
|
||||||
setCurrentSwipe: (index: number, swipe: number) => void;
|
setCurrentSwipe: (index: number, swipe: number) => void;
|
||||||
addSwipe: (index: number, content: string) => void;
|
addSwipe: (index: number, content: string) => void;
|
||||||
|
|
@ -63,6 +66,7 @@ export const loadContext = (): IContext => {
|
||||||
lore: '',
|
lore: '',
|
||||||
userPrompt: `{% if prompt %}{% if isStart %}Start{% else %}Continue{% endif %} this story, taking information into account: {{ prompt | trim }}
|
userPrompt: `{% if prompt %}{% if isStart %}Start{% else %}Continue{% endif %} this story, taking information into account: {{ prompt | trim }}
|
||||||
Remember that this story should be infinite and go forever. Avoid cliffhangers and pauses, be creative.{% elif isStart %}Write a novel using information above as a reference. Make sure to follow the lore exactly and avoid cliffhangers.{% else %}Continue the story forward. Avoid cliffhangers and pauses.{% endif %}`,
|
Remember that this story should be infinite and go forever. Avoid cliffhangers and pauses, be creative.{% elif isStart %}Write a novel using information above as a reference. Make sure to follow the lore exactly and avoid cliffhangers.{% else %}Continue the story forward. Avoid cliffhangers and pauses.{% endif %}`,
|
||||||
|
summarizePrompt: 'Make the following text shorter, keeping all important details:\n\n{{ message }}\n\nYour answer should only contain the shortened text.',
|
||||||
bannedWords: [],
|
bannedWords: [],
|
||||||
messages: [],
|
messages: [],
|
||||||
triggerNext: false,
|
triggerNext: false,
|
||||||
|
|
@ -92,6 +96,7 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
|
||||||
const [lore, setLore] = useInputState(loadedContext.lore);
|
const [lore, setLore] = useInputState(loadedContext.lore);
|
||||||
const [systemPrompt, setSystemPrompt] = useInputState(loadedContext.systemPrompt);
|
const [systemPrompt, setSystemPrompt] = useInputState(loadedContext.systemPrompt);
|
||||||
const [userPrompt, setUserPrompt] = useInputState(loadedContext.userPrompt);
|
const [userPrompt, setUserPrompt] = useInputState(loadedContext.userPrompt);
|
||||||
|
const [summarizePrompt, setSummarizePrompt] = useInputState(loadedContext.summarizePrompt);
|
||||||
const [bannedWords, setBannedWords] = useState<string[]>(loadedContext.bannedWords);
|
const [bannedWords, setBannedWords] = useState<string[]>(loadedContext.bannedWords);
|
||||||
const [messages, setMessages] = useState(loadedContext.messages);
|
const [messages, setMessages] = useState(loadedContext.messages);
|
||||||
|
|
||||||
|
|
@ -103,6 +108,7 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
|
||||||
setInstruct,
|
setInstruct,
|
||||||
setSystemPrompt,
|
setSystemPrompt,
|
||||||
setUserPrompt,
|
setUserPrompt,
|
||||||
|
setSummarizePrompt,
|
||||||
setLore,
|
setLore,
|
||||||
setTriggerNext,
|
setTriggerNext,
|
||||||
setBannedWords: (words) => setBannedWords([...words]),
|
setBannedWords: (words) => setBannedWords([...words]),
|
||||||
|
|
@ -115,9 +121,11 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
|
||||||
]);
|
]);
|
||||||
setTriggerNext(triggerNext);
|
setTriggerNext(triggerNext);
|
||||||
},
|
},
|
||||||
editMessage: (index, content, triggerNext = false) => {
|
editMessage: (index, content) => {
|
||||||
setMessages(messages => MessageTools.updateContent(messages, index, content));
|
setMessages(messages => MessageTools.updateSwipe(messages, index, { content }));
|
||||||
setTriggerNext(triggerNext);
|
},
|
||||||
|
editSummary: (index, summary) => {
|
||||||
|
setMessages(messages => MessageTools.updateSwipe(messages, index, { summary }));
|
||||||
},
|
},
|
||||||
deleteMessage: (index) => setMessages(messages =>
|
deleteMessage: (index) => setMessages(messages =>
|
||||||
messages.filter((_, i) => i !== index)
|
messages.filter((_, i) => i !== index)
|
||||||
|
|
@ -181,6 +189,7 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
|
||||||
systemPrompt,
|
systemPrompt,
|
||||||
lore,
|
lore,
|
||||||
userPrompt,
|
userPrompt,
|
||||||
|
summarizePrompt,
|
||||||
bannedWords,
|
bannedWords,
|
||||||
messages,
|
messages,
|
||||||
triggerNext,
|
triggerNext,
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ export namespace Huggingface {
|
||||||
};
|
};
|
||||||
|
|
||||||
const templateCache: Record<string, string> = loadCache();
|
const templateCache: Record<string, string> = loadCache();
|
||||||
|
const compiledTemplates = new Map<string, Template>();
|
||||||
|
|
||||||
const hasField = <T extends string>(obj: unknown, field: T): obj is Record<T, unknown> => (
|
const hasField = <T extends string>(obj: unknown, field: T): obj is Record<T, unknown> => (
|
||||||
obj != null && typeof obj === 'object' && (field in obj)
|
obj != null && typeof obj === 'object' && (field in obj)
|
||||||
|
|
@ -256,15 +257,29 @@ export namespace Huggingface {
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const applyChatTemplate = (templateString: string, messages: ITemplateMessage[], functions?: IFunction[]) => {
|
export const applyChatTemplate = (templateString: string, messages: ITemplateMessage[], functions?: IFunction[]) => (
|
||||||
const template = new Template(templateString);
|
applyTemplate(templateString, {
|
||||||
|
|
||||||
const prompt = template.render({
|
|
||||||
messages,
|
messages,
|
||||||
add_generation_prompt: true,
|
add_generation_prompt: true,
|
||||||
tools: functions?.map(convertFunctionToTool),
|
tools: functions?.map(convertFunctionToTool),
|
||||||
});
|
})
|
||||||
|
);
|
||||||
|
|
||||||
return prompt;
|
export const applyTemplate = (templateString: string, args: Record<string, any>): string => {
|
||||||
};
|
try {
|
||||||
|
let template = compiledTemplates.get(templateString);
|
||||||
|
if (!template) {
|
||||||
|
template = new Template(templateString);
|
||||||
|
compiledTemplates.set(templateString, template);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = template.render(args);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[applyTemplate] error:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ import messageSound from './assets/message.mp3';
|
||||||
|
|
||||||
export interface ISwipe {
|
export interface ISwipe {
|
||||||
content: string;
|
content: string;
|
||||||
|
summary?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessage {
|
export interface IMessage {
|
||||||
|
|
@ -94,15 +95,15 @@ export namespace MessageTools {
|
||||||
if (latestEnd > 0) {
|
if (latestEnd > 0) {
|
||||||
text = text.slice(0, latestEnd + 1);
|
text = text.slice(0, latestEnd + 1);
|
||||||
}
|
}
|
||||||
return text.trimEnd();
|
return text.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateContent = (messages: IMessage[], index: number, content: string) => (
|
export const updateSwipe = (messages: IMessage[], index: number, update: Partial<ISwipe>) => (
|
||||||
messages.map(
|
messages.map(
|
||||||
(m, i) => ({
|
(m, i) => ({
|
||||||
...m,
|
...m,
|
||||||
swipes: i === index
|
swipes: i === index
|
||||||
? m.swipes.map((s, si) => (si === m.currentSwipe ? { content } : s))
|
? m.swipes.map((s, si) => (si === m.currentSwipe ? { ...s, ...update } : s))
|
||||||
: m.swipes
|
: m.swipes
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue