import { useState, useEffect, useMemo, HTMLProps } from "react"; import EmojiPicker, { Theme as EmojiTheme } from "emoji-picker-react"; import styles from "./settings.module.scss"; import ResetIcon from "../icons/reload.svg"; import CloseIcon from "../icons/close.svg"; import ClearIcon from "../icons/clear.svg"; import EditIcon from "../icons/edit.svg"; import EyeIcon from "../icons/eye.svg"; import EyeOffIcon from "../icons/eye-off.svg"; import { List, ListItem, Popover, showToast } from "./ui-lib"; import { IconButton } from "./button"; import { SubmitKey, useChatStore, Theme, ALL_MODELS, useUpdateStore, useAccessStore, ModalConfigValidator, } from "../store"; import { Avatar } from "./chat"; import Locale, { AllLangs, changeLang, getLang } from "../locales"; import { getCurrentVersion, getEmojiUrl } from "../utils"; import Link from "next/link"; import { UPDATE_URL } from "../constant"; import { SearchService, usePromptStore } from "../store/prompt"; import { requestUsage } from "../requests"; import { ErrorBoundary } from "./error"; function SettingItem(props: { title: string; subTitle?: string; children: JSX.Element; }) { return (
{props.title}
{props.subTitle && (
{props.subTitle}
)}
{props.children}
); } function PasswordInput(props: HTMLProps) { const [visible, setVisible] = useState(false); function changeVisibility() { setVisible(!visible); } return (
: } onClick={changeVisibility} className={styles["password-eye"]} />
); } export function Settings(props: { closeSettings: () => void }) { const [showEmojiPicker, setShowEmojiPicker] = useState(false); const [config, updateConfig, resetConfig, clearAllData, clearSessions] = useChatStore((state) => [ state.config, state.updateConfig, state.resetConfig, state.clearAllData, state.clearSessions, ]); const updateStore = useUpdateStore(); const [checkingUpdate, setCheckingUpdate] = useState(false); const currentId = getCurrentVersion(); const remoteId = updateStore.remoteId; const hasNewVersion = currentId !== remoteId; function checkUpdate(force = false) { setCheckingUpdate(true); updateStore.getLatestCommitId(force).then(() => { setCheckingUpdate(false); }); } const [usage, setUsage] = useState<{ used?: number; subscription?: number; }>(); const [loadingUsage, setLoadingUsage] = useState(false); function checkUsage() { setLoadingUsage(true); requestUsage() .then((res) => setUsage(res)) .finally(() => { setLoadingUsage(false); }); } const accessStore = useAccessStore(); const enabledAccessControl = useMemo( () => accessStore.enabledAccessControl(), // eslint-disable-next-line react-hooks/exhaustive-deps [], ); const promptStore = usePromptStore(); const builtinCount = SearchService.count.builtin; const customCount = promptStore.prompts.size ?? 0; const showUsage = !!accessStore.token || !!accessStore.accessCode; useEffect(() => { checkUpdate(); showUsage && checkUsage(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return (
{Locale.Settings.Title}
{Locale.Settings.SubTitle}
} onClick={clearSessions} bordered title={Locale.Settings.Actions.ClearAll} />
} onClick={resetConfig} bordered title={Locale.Settings.Actions.ResetAll} />
} onClick={props.closeSettings} bordered title={Locale.Settings.Actions.Close} />
setShowEmojiPicker(false)} content={ { updateConfig((config) => (config.avatar = e.unified)); setShowEmojiPicker(false); }} /> } open={showEmojiPicker} >
setShowEmojiPicker(true)} >
{checkingUpdate ? (
) : hasNewVersion ? ( {Locale.Settings.Update.GoToUpdate} ) : ( } text={Locale.Settings.Update.CheckUpdate} onClick={() => checkUpdate(true)} /> )}
{Locale.Settings.Theme}
updateConfig( (config) => (config.fontSize = Number.parseInt(e.currentTarget.value)), ) } > updateConfig( (config) => (config.tightBorder = e.currentTarget.checked), ) } > updateConfig( (config) => (config.sendPreviewBubble = e.currentTarget.checked), ) } > updateConfig( (config) => (config.disablePromptHint = e.currentTarget.checked), ) } > } text={Locale.Settings.Prompt.Edit} onClick={() => showToast(Locale.WIP)} /> {enabledAccessControl ? ( { accessStore.updateCode(e.currentTarget.value); }} /> ) : ( <> )} { accessStore.updateToken(e.currentTarget.value); }} /> {!showUsage || loadingUsage ? (
) : ( } text={Locale.Settings.Usage.Check} onClick={checkUsage} /> )} updateConfig( (config) => (config.historyMessageCount = e.target.valueAsNumber), ) } > updateConfig( (config) => (config.compressMessageLengthThreshold = e.currentTarget.valueAsNumber), ) } > { updateConfig( (config) => (config.modelConfig.temperature = ModalConfigValidator.temperature( e.currentTarget.valueAsNumber, )), ); }} > updateConfig( (config) => (config.modelConfig.max_tokens = ModalConfigValidator.max_tokens( e.currentTarget.valueAsNumber, )), ) } > { updateConfig( (config) => (config.modelConfig.presence_penalty = ModalConfigValidator.presence_penalty( e.currentTarget.valueAsNumber, )), ); }} >
); }