140 lines
6.2 KiB
TypeScript
140 lines
6.2 KiB
TypeScript
import { useCallback, useContext, useMemo } from "preact/hooks";
|
|
import { useBool } from "@common/hooks/useBool";
|
|
import { Modal } from "@common/components/modal/Modal";
|
|
|
|
import { StateContext } from "../../contexts/state";
|
|
import { LLMContext } from "../../contexts/llm";
|
|
import { MiniChat } from "../minichat/minichat";
|
|
import { AutoTextarea } from "../autoTextarea";
|
|
import { Ace } from "../ace";
|
|
import { ConnectionEditor } from "./connectionEditor";
|
|
|
|
import styles from './header.module.css';
|
|
|
|
export const Header = () => {
|
|
const { contextLength, promptTokens, modelName, spentKudos } = useContext(LLMContext);
|
|
const {
|
|
messages, connection, systemPrompt, lore, userPrompt, bannedWords, summarizePrompt, summaryEnabled, totalSpentKudos,
|
|
setSystemPrompt, setLore, setUserPrompt, addSwipe, setBannedWords, setInstruct, setSummarizePrompt, setSummaryEnabled, setConnection,
|
|
} = useContext(StateContext);
|
|
|
|
const connectionsOpen = useBool();
|
|
const loreOpen = useBool();
|
|
const promptsOpen = useBool();
|
|
const genparamsOpen = useBool();
|
|
const assistantOpen = useBool();
|
|
const isOnline = useMemo(() => contextLength > 0, [contextLength]);
|
|
|
|
const bannedWordsInput = useMemo(() => bannedWords.join('\n'), [bannedWords]);
|
|
|
|
const handleAssistantAddSwipe = useCallback((answer: string) => {
|
|
const index = messages.findLastIndex(m => m.role === 'assistant');
|
|
addSwipe(index, answer);
|
|
assistantOpen.setFalse();
|
|
}, [addSwipe, messages]);
|
|
|
|
const handleSetBannedWords = useCallback((e: Event) => {
|
|
if (e.target instanceof HTMLTextAreaElement) {
|
|
const words = e.target.value.split('\n');
|
|
setBannedWords(words);
|
|
}
|
|
}, [setBannedWords]);
|
|
|
|
const handleBlurBannedWords = useCallback((e: Event) => {
|
|
if (e.target instanceof HTMLTextAreaElement) {
|
|
const words = e.target.value.toLowerCase().split('\n').sort();
|
|
setBannedWords(words);
|
|
}
|
|
}, [setBannedWords]);
|
|
|
|
const handleSetSummaryEnabled = useCallback((e: Event) => {
|
|
if (e.target instanceof HTMLInputElement) {
|
|
setSummaryEnabled(e.target.checked);
|
|
}
|
|
}, [setSummaryEnabled]);
|
|
|
|
return (
|
|
<div class={styles.header}>
|
|
<div class={styles.inputs}>
|
|
<div class={styles.buttons}>
|
|
<button class={`icon ${isOnline ? styles.online: styles.offline}`} onClick={connectionsOpen.setTrue} title='Connection settings'>
|
|
🔌
|
|
</button>
|
|
</div>
|
|
<div class={styles.info}>
|
|
<span>{modelName}</span>
|
|
<span>📃{promptTokens}/{contextLength}</span>
|
|
<span>💲{spentKudos}</span>
|
|
<span>💰{totalSpentKudos}</span>
|
|
</div>
|
|
</div>
|
|
<div class={styles.buttons}>
|
|
<button class='icon color' title='Edit lore' onClick={loreOpen.setTrue}>
|
|
🌍
|
|
</button>
|
|
<button class='icon color' title='Generation parameters' onClick={genparamsOpen.setTrue}>
|
|
⚙
|
|
</button>
|
|
<button class='icon color' title='Edit prompts' onClick={promptsOpen.setTrue}>
|
|
📃
|
|
</button>
|
|
</div>
|
|
<div class={styles.buttons}>
|
|
<button class='icon' onClick={assistantOpen.setTrue} title='Ask assistant'>
|
|
❓
|
|
</button>
|
|
</div>
|
|
<Modal open={connectionsOpen.value} onClose={connectionsOpen.setFalse}>
|
|
<h3 class={styles.modalTitle}>Connection settings</h3>
|
|
<ConnectionEditor connection={connection} setConnection={setConnection} />
|
|
</Modal>
|
|
<Modal open={loreOpen.value} onClose={loreOpen.setFalse}>
|
|
<h3 class={styles.modalTitle}>Lore Editor</h3>
|
|
<AutoTextarea
|
|
value={lore}
|
|
onInput={setLore}
|
|
placeholder="Describe your world, for example: World of Awoo has big mountains and wide rivers."
|
|
/>
|
|
</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}>
|
|
<h3 class={styles.modalTitle}>Prompts Editor</h3>
|
|
<div className={styles.scrollPane}>
|
|
<h4 class={styles.modalTitle}>System prompt</h4>
|
|
<AutoTextarea value={systemPrompt} onInput={setSystemPrompt} />
|
|
<hr />
|
|
<h4 class={styles.modalTitle}>User prompt template</h4>
|
|
<Ace value={userPrompt} onInput={setUserPrompt} />
|
|
<hr />
|
|
<h4 class={styles.modalTitle}>Summary template</h4>
|
|
<Ace value={summarizePrompt} onInput={setSummarizePrompt} />
|
|
<label>
|
|
<input type='checkbox' checked={summaryEnabled} onChange={handleSetSummaryEnabled} />
|
|
Enable summarization
|
|
</label>
|
|
<hr />
|
|
<h4 class={styles.modalTitle}>Instruct template</h4>
|
|
<Ace value={connection.instruct} onInput={setInstruct} />
|
|
</div>
|
|
</Modal>
|
|
<MiniChat
|
|
history={messages}
|
|
open={assistantOpen.value}
|
|
onClose={assistantOpen.setFalse}
|
|
buttons={{ 'Add swipe': handleAssistantAddSwipe }}
|
|
/>
|
|
</div>
|
|
);
|
|
} |